path_tree.js 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127
  1. /**
  2. * 构建pathTree
  3. * 可动态加载子节点,要求子节点获取接口按/xxx/get-children定义
  4. * @param {Object} setting - 设置
  5. * @returns {PathTree}
  6. */
  7. 'use strict';
  8. class PosData {
  9. /**
  10. * 构造函数
  11. * @param {id|Number, masterId|Number} setting
  12. */
  13. constructor (setting) {
  14. // 无索引
  15. this.datas = null;
  16. // 以key为索引
  17. this.items = {};
  18. // 以分类id为索引的有序
  19. this.ledgerPos = {};
  20. // pos设置
  21. this.setting = setting;
  22. }
  23. /**
  24. * 加载部位明细数据
  25. * @param datas
  26. */
  27. loadDatas(datas) {
  28. this.datas = datas;
  29. for (const data of this.datas) {
  30. const key = itemsPre + data[this.setting.id];
  31. this.items[key] = data;
  32. const masterKey = itemsPre + data[this.setting.ledgerId];
  33. if (!this.ledgerPos[masterKey]) {
  34. this.ledgerPos[masterKey] = [];
  35. }
  36. this.ledgerPos[masterKey].push(data);
  37. }
  38. }
  39. /**
  40. * 更新数据
  41. * @param datas
  42. */
  43. updateDatas(data) {
  44. const datas = data instanceof Array ? data : [data];
  45. for (const d of datas) {
  46. const key = itemsPre + d[this.setting.id];
  47. if (!this.items[key]) {
  48. this.datas.push(d);
  49. this.items[key] = d;
  50. const masterKey = itemsPre + d[this.setting.ledgerId];
  51. if (!this.ledgerPos[masterKey]) {
  52. this.ledgerPos[masterKey] = [];
  53. }
  54. this.ledgerPos[masterKey].push(d);
  55. } else {
  56. const pos = this.items[key];
  57. for (const prop in d) {
  58. pos[prop] = d[prop];
  59. }
  60. }
  61. }
  62. }
  63. /**
  64. * 移除数据
  65. * @param datas
  66. */
  67. removeDatas(data) {
  68. const datas = data instanceof Array ? data : [data];
  69. for (let i = datas.length - 1; i >= 0; i--) {
  70. const d = datas[i];
  71. this.datas.splice(this.datas.indexOf(d), 1);
  72. const key = itemsPre + d[this.setting.id];
  73. delete this.items[key];
  74. const masterKey = itemsPre + d[this.setting.ledgerId];
  75. const range = this.ledgerPos[masterKey];
  76. range.splice(range.indexOf(d), 1);
  77. if (range.length === 0) {
  78. delete this.ledgerPos[masterKey];
  79. }
  80. }
  81. }
  82. /**
  83. * 移除数据 - 根据分类id
  84. * @param mid
  85. */
  86. removeDatasByMasterId (mid) {
  87. const masterKey = itemsPre + mid;
  88. const range = this.ledgerPos[masterKey];
  89. if (range) {
  90. delete this.ledgerPos[masterKey];
  91. for (const r of range) {
  92. this.datas.splice(this.datas.indexOf(r), 1);
  93. const key = itemsPre + r[this.setting.id];
  94. delete this.items[key];
  95. }
  96. }
  97. }
  98. getPos(id) {
  99. return this.items[itemsPre + id];
  100. }
  101. getLedgerPos(mid) {
  102. return this.ledgerPos[itemsPre + mid];
  103. }
  104. /**
  105. * 计算全部
  106. */
  107. calculateAll() {
  108. if (!this.setting.calcFun) { return; }
  109. for (const pos of this.datas) {
  110. this.setting.calcFun(pos);
  111. }
  112. }
  113. }
  114. class StagePosData extends PosData {
  115. loadStageData(datas, fieldPre, fields) {
  116. if (!datas) { return; }
  117. datas = datas instanceof Array ? datas : [datas];
  118. const loadedData = [];
  119. for (const data of datas) {
  120. let node = this.getPos(data.pid);
  121. if (node) {
  122. for (const prop of fields) {
  123. if (data[fieldPre + prop] !== undefined) {
  124. node[fieldPre + prop] = data[prop];
  125. }
  126. }
  127. if (this.setting.calcFun) {
  128. this.setting.calcFun(node);
  129. }
  130. loadedData.push(node);
  131. }
  132. }
  133. }
  134. loadPreStageData(datas) {
  135. this.loadStageData(datas, 'pre_', this.setting.updateFields);
  136. }
  137. loadCurStageData(datas) {
  138. this.loadStageData(datas, '', this.setting.updateFields);
  139. }
  140. }
  141. class MasterPosData extends PosData {
  142. /**
  143. * 构造函数
  144. * @param {id|Number, masterId|Number} setting
  145. */
  146. constructor (setting) {
  147. super(setting);
  148. // 关联索引
  149. this.masterItems = {};
  150. }
  151. /**
  152. * 加载主数据
  153. * @param datas
  154. */
  155. loadDatas (datas) {
  156. super.loadDatas(datas);
  157. // 清空旧数据
  158. this.masterItems = {};
  159. // minor数据缓存
  160. this.minorData = {};
  161. // 加载全部数据
  162. for (const data of this.datas) {
  163. const keyName = itemsPre + data[this.setting.masterId];
  164. this.masterItems[keyName] = data;
  165. }
  166. }
  167. /**
  168. * 根据关联id,查找节点
  169. * @param id
  170. * @returns {*}
  171. */
  172. getMasterItems(id) {
  173. return this.masterItems[itemsPre + id];
  174. }
  175. /**
  176. * 加载关联数据
  177. *
  178. * @param {Array|Object}datas - 需要关联的数据
  179. * @param {String} fieldPre - 关联字段前缀(关联结果)
  180. * @param {Array} fields - 关联字段
  181. * @returns {Array}
  182. */
  183. loadMinorData(datas, fieldSuf, fields) {
  184. if (!datas) { return; }
  185. datas = datas instanceof Array ? datas : [datas];
  186. this.minorData[fieldSuf] = datas;
  187. const loadedData = [];
  188. for (const data of datas) {
  189. let node = this.getMasterItems(data[this.setting.minorId]);
  190. if (node) {
  191. for (const prop of fields) {
  192. if (data[prop] !== undefined) {
  193. node[prop + fieldSuf] = data[prop];
  194. }
  195. }
  196. loadedData.push(node);
  197. }
  198. }
  199. return loadedData;
  200. }
  201. }
  202. const itemsPre = 'id_';
  203. const createNewPathTree = function (type, setting) {
  204. class BaseTree {
  205. /**
  206. * 构造函数
  207. */
  208. constructor (setting) {
  209. // 无索引
  210. this.datas = [];
  211. // 以key为索引
  212. this.items = {};
  213. // 以排序为索引
  214. this.nodes = [];
  215. // 根节点
  216. this.children = [];
  217. // 树设置
  218. this.setting = setting;
  219. }
  220. /**
  221. * 树结构根据显示排序
  222. */
  223. sortTreeNode (isResort) {
  224. const self = this;
  225. const addSortNodes = function (nodes) {
  226. if (!nodes) { return }
  227. for (let i = 0; i < nodes.length; i++) {
  228. self.nodes.push(nodes[i]);
  229. nodes[i].index = self.nodes.length - 1;
  230. if (!isResort) {
  231. nodes[i].children = self.getChildren(nodes[i]);
  232. }
  233. addSortNodes(nodes[i].children);
  234. }
  235. };
  236. self.nodes = [];
  237. this.children = this.getChildren(null);
  238. addSortNodes(this.getChildren(null));
  239. }
  240. /**
  241. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  242. * @param datas
  243. */
  244. loadDatas (datas) {
  245. // 清空旧数据
  246. this.items = {};
  247. this.nodes = [];
  248. this.datas = [];
  249. this.children = [];
  250. // 加载全部数据
  251. for (const data of datas) {
  252. const keyName = itemsPre + data[this.setting.id];
  253. if (!this.items[keyName]) {
  254. this.items[keyName] = JSON.parse(JSON.stringify(data));
  255. this.datas.push(this.items[keyName]);
  256. }
  257. }
  258. this.sortTreeNode();
  259. for (const node of this.nodes) {
  260. node.expanded = node.children.length > 0;
  261. node.visible = true;
  262. }
  263. }
  264. getItemsByIndex(index) {
  265. return this.nodes[index];
  266. }
  267. /**
  268. * 根据id获取树结构节点数据
  269. * @param {Number} id
  270. * @returns {Object}
  271. */
  272. getItems (id) {
  273. return this.items[itemsPre + id];
  274. };
  275. /**
  276. * 查找node的parent
  277. * @param {Object} node
  278. * @returns {Object}
  279. */
  280. getParent (node) {
  281. return this.getItems(node[this.setting.pid]);
  282. };
  283. /**
  284. * 根据path查找完整节点
  285. * @param {Number} path
  286. */
  287. getFullPathNodes (path) {
  288. const self = this, ids = path.split('.');
  289. if (ids.length > 0) {
  290. return this.nodes.filter((x) => {
  291. return ids.indexOf('' + x[self.setting.id]) >= 0;
  292. });
  293. } else {
  294. return [];
  295. }
  296. };
  297. /**
  298. * 查询node的已下载子节点
  299. * @param {Object} node
  300. * @returns {Array}
  301. */
  302. getChildren (node) {
  303. const setting = this.setting;
  304. const pid = node ? node[setting.id] : setting.rootId;
  305. const children = this.datas.filter(function (x) {
  306. return x[setting.pid] === pid;
  307. });
  308. children.sort(function (a, b) {
  309. return a.order - b.order;
  310. });
  311. return children;
  312. };
  313. /**
  314. * 查询node的已下载的全部后代
  315. * @param {Object} node
  316. * @returns {Array}
  317. */
  318. getPosterity (node) {
  319. const reg = new RegExp('^' + node.full_path + '.');
  320. return this.datas.filter(function (x) {
  321. return reg.test(x.full_path);
  322. })
  323. };
  324. /**
  325. * 查询node是否是父节点的最后一个子节点
  326. * @param {Object} node
  327. * @returns {boolean}
  328. */
  329. isLastSibling (node) {
  330. const siblings = this.getChildren(this.getParent(node));
  331. return node.order === siblings[siblings.length - 1].order;
  332. };
  333. /**
  334. * 刷新子节点是否可见
  335. * @param {Object} node
  336. * @private
  337. */
  338. _refreshChildrenVisible (node) {
  339. if (!node.children) {
  340. node.children = this.getChildren(node);
  341. }
  342. if (node.children && node.children.length > 0) {
  343. for (const child of node.children) {
  344. child.visible = node.expanded && node.visible;
  345. this._refreshChildrenVisible(child);
  346. }
  347. }
  348. };
  349. /**
  350. * 设置节点是否展开, 并控制子节点可见
  351. * @param {Object} node
  352. * @param {Boolean} expanded
  353. */
  354. setExpanded (node, expanded) {
  355. node.expanded = expanded;
  356. this._refreshChildrenVisible(node);
  357. };
  358. /**
  359. * 提取节点key和索引数据
  360. * @param {Object} node - 节点
  361. * @returns {key}
  362. */
  363. getNodeKeyData (node) {
  364. const data = {};
  365. for (const key of this.setting.keys) {
  366. data[key] = node[key];
  367. }
  368. return data;
  369. };
  370. /**
  371. * 得到树结构构成id
  372. * @param node
  373. * @returns {*}
  374. */
  375. getNodeKey (node) {
  376. return node[this.setting.id];
  377. };
  378. /**
  379. * 递归 设置节点展开状态
  380. * @param {Array} nodes - 需要设置状态的节点
  381. * @param {Object} parent - nodes的父节点
  382. * @param {Function} checkFun - 判断节点展开状态的方法
  383. * @private
  384. */
  385. _recursiveExpand(nodes, parent, checkFun) {
  386. for (const node of nodes) {
  387. node.expanded = checkFun(node);
  388. node.visible = parent ? (parent.expanded && parent.visible) : true;
  389. this._recursiveExpand(node.children, node, checkFun);
  390. }
  391. }
  392. /**
  393. * 自定义展开规则
  394. * @param checkFun
  395. */
  396. expandByCustom(checkFun) {
  397. this._recursiveExpand(this.children, null, checkFun);
  398. }
  399. /**
  400. * 展开到第几层
  401. * @param {Number} level - 展开层数
  402. */
  403. expandByLevel(level) {
  404. // function recursiveExpand(nodes, parent) {
  405. // for (const node of nodes) {
  406. // node.expanded = node.level < level;
  407. // node.visible = parent ? (parent.expanded && parent.visible) : true;
  408. // recursiveExpand(node.children, node);
  409. // }
  410. // }
  411. // recursiveExpand(this.children);
  412. this.expandByCustom(function (n) {
  413. return n.level < level;
  414. });
  415. }
  416. }
  417. class MeasureTree extends BaseTree {
  418. addData (datas) {
  419. const loadedData = [];
  420. for (const data of datas) {
  421. let node = this.getItems(data[this.setting.id]);
  422. if (node) {
  423. for (const prop in node) {
  424. if (data[prop] !== undefined) {
  425. node[prop] = data[prop];
  426. }
  427. }
  428. loadedData.push(node);
  429. } else {
  430. const keyName = itemsPre + data[this.setting.id];
  431. const node = JSON.parse(JSON.stringify(data));
  432. this.items[keyName] = node;
  433. this.datas.push(node);
  434. node.expanded = false;
  435. node.visible = true;
  436. loadedData.push(node);
  437. }
  438. }
  439. this.sortTreeNode();
  440. for (const node of loadedData) {
  441. const children = node.children;
  442. if (!node.expanded && children.length > 0) {
  443. node.expanded = true;
  444. this._refreshChildrenVisible(node);
  445. }
  446. }
  447. return loadedData;
  448. }
  449. removeData (datas) {
  450. datas.sort(function (a, b) {
  451. return b.level - a.level;
  452. });
  453. const removeArrayData = function (array, data) {
  454. const index = array.indexOf(data);
  455. array.splice(index, 1);
  456. };
  457. for (const data of datas) {
  458. const node = this.getItems(data[this.setting.id]);
  459. if (node && this.getChildren(node).length === 0) {
  460. delete this.items[itemsPre + node[this.setting.id]];
  461. if (node[this.setting.pid] !== this.setting.rootId) {
  462. const parent = this.items[itemsPre + node[this.setting.pid]];
  463. removeArrayData(parent.children, node);
  464. }
  465. removeArrayData(this.datas, node);
  466. removeArrayData(this.nodes, node);
  467. }
  468. }
  469. };
  470. loadLeafData (data) {
  471. const datas = data instanceof Array ? data : [data];
  472. for (const d of datas) {
  473. let node = this.getItems(d[this.setting.id]);
  474. if (node && node.is_leaf) {
  475. for (const prop in node) {
  476. if (data[prop] !== undefined) {
  477. node[prop] = d[prop];
  478. }
  479. }
  480. }
  481. }
  482. };
  483. }
  484. class FxTree extends BaseTree {
  485. /**
  486. * 检查节点是否是最底层项目节
  487. * @param node
  488. * @returns {boolean}
  489. */
  490. isLeafXmj(node) {
  491. for (const child of node.children) {
  492. if (!child.b_code || child.b_code === '') {
  493. return false;
  494. }
  495. }
  496. return true;
  497. }
  498. /**
  499. * 展开至最底层项目节
  500. */
  501. expandToLeafXmj() {
  502. const self = this;
  503. this.expandByCustom(function (node) {
  504. if (node.b_code && node.b_code !== '') {
  505. return false;
  506. } else {
  507. return !self.isLeafXmj(node);
  508. }
  509. })
  510. }
  511. }
  512. class LedgerTree extends FxTree {
  513. /**
  514. * 加载数据(动态),只加载不同部分
  515. * @param {Array} datas
  516. * @return {Array} 加载到树的数据
  517. * @privateA
  518. */
  519. _updateData (datas) {
  520. datas = datas instanceof Array ? datas : [datas];
  521. const loadedData = [];
  522. for (const data of datas) {
  523. let node = this.getItems(data[this.setting.id]);
  524. if (node) {
  525. for (const prop in node) {
  526. if (data[prop] !== undefined) {
  527. node[prop] = data[prop];
  528. }
  529. }
  530. loadedData.push(node);
  531. }
  532. }
  533. for (const node of loadedData) {
  534. const children = this.getChildren(node);
  535. node.expanded = children.length > 0 && children[0].visible;
  536. }
  537. this.sortTreeNode(true);
  538. return loadedData;
  539. };
  540. /**
  541. * 加载数据(动态),只加载不同部分
  542. * @param {Array} datas
  543. * @return {Array} 加载到树的数据
  544. * @privateA
  545. */
  546. _loadData (datas) {
  547. datas = datas instanceof Array ? datas : [datas];
  548. const loadedData = [], resortData = [];
  549. for (const data of datas) {
  550. let node = this.getItems(data[this.setting.id]);
  551. if (node) {
  552. const parent = this.getItems(node[this.setting.pid]);
  553. for (const prop in node) {
  554. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  555. node[prop] = data[prop];
  556. if (parent && resortData.indexOf(parent) === -1) {
  557. resortData.push(parent);
  558. }
  559. }
  560. }
  561. loadedData.push(node);
  562. } else {
  563. const keyName = itemsPre + data[this.setting.id];
  564. const node = JSON.parse(JSON.stringify(data));
  565. this.items[keyName] = node;
  566. this.datas.push(node);
  567. node.expanded = false;
  568. node.visible = true;
  569. loadedData.push(node);
  570. if (resortData.indexOf(node) === -1) {
  571. resortData.push(node);
  572. }
  573. const parent = this.getItems(node[this.setting.pid]);
  574. if (parent && resortData.indexOf(parent) === -1) {
  575. resortData.push(parent);
  576. }
  577. }
  578. }
  579. for (const node of resortData) {
  580. node.children = this.getChildren(node);
  581. }
  582. this.sortTreeNode(true);
  583. for (const node of loadedData) {
  584. if (!node.expanded) {
  585. this.setExpanded(node, true);
  586. }
  587. }
  588. return loadedData;
  589. };
  590. /**
  591. * 清理数据(动态)
  592. * @param datas
  593. * @private
  594. */
  595. _freeData (datas) {
  596. datas = datas instanceof Array ? datas : [datas];
  597. const freeDatas = [];
  598. const removeArrayData = function (array, data) {
  599. const index = array.indexOf(data);
  600. array.splice(index, 1);
  601. };
  602. for (const data of datas) {
  603. const node = this.getItems(data[this.setting.id]);
  604. if (node) {
  605. freeDatas.push(node);
  606. delete this.items[itemsPre + node[this.setting.id]];
  607. if (node[this.setting.pid] !== this.setting.rootId) {
  608. const parent = this.getItems(node[this.setting.pid]);
  609. if (parent) {
  610. removeArrayData(parent.children, node);
  611. }
  612. }
  613. removeArrayData(this.datas, node);
  614. removeArrayData(this.nodes, node);
  615. }
  616. }
  617. return freeDatas;
  618. };
  619. /**
  620. * 加载需展开的数据
  621. * @param {Array} datas
  622. * @returns {Array}
  623. * @private
  624. */
  625. _loadExpandData (datas) {
  626. datas = datas instanceof Array ? datas : [datas];
  627. const loadedData = [], existData = [], expandData = [], resortData = [];
  628. for (const data of datas) {
  629. let node = this.getItems(data[this.setting.id]);
  630. if (node) {
  631. existData.push(node);
  632. } else {
  633. const keyName = itemsPre + data[this.setting.id];
  634. const node = JSON.parse(JSON.stringify(data));
  635. this.items[keyName] = node;
  636. this.datas.push(node);
  637. node.expanded = false;
  638. node.visible = true;
  639. loadedData.push(node);
  640. if (resortData.indexOf(node) === -1) {
  641. resortData.push(node);
  642. }
  643. const parent = this.getItems(node[this.setting.pid]);
  644. if (parent && resortData.indexOf(parent) === -1) {
  645. resortData.push(parent);
  646. }
  647. }
  648. }
  649. for (const node of resortData) {
  650. node.children = this.getChildren(node);
  651. }
  652. this.sortTreeNode(true);
  653. for (const node of loadedData) {
  654. if (!node.expanded) {
  655. this.setExpanded(node, true);
  656. }
  657. }
  658. for (const node of existData) {
  659. const parent = this.getItems(node[this.setting.pid]);
  660. if (expandData.indexOf(parent) === -1) {
  661. expandData.push(parent);
  662. if (!parent.expanded) {
  663. this.setExpanded(parent, true);
  664. }
  665. }
  666. if (!node.expanded) {
  667. this.setExpanded(node, true);
  668. }
  669. }
  670. return [loadedData, expandData];
  671. };
  672. /**
  673. *
  674. * @param parent
  675. * @param node
  676. * @private
  677. */
  678. _getNodesParents(parents, nodes) {
  679. for (const node of nodes) {
  680. const parent = this.getParent(node);
  681. if (parent) {
  682. const paths = this.getFullPathNodes(parent.full_path);
  683. for (const p of paths) {
  684. if (parents.indexOf(p) === -1) {
  685. parents.push(p);
  686. }
  687. }
  688. }
  689. if (this.getItems(node.id) && node.children.length > 0) {
  690. parents.push(node);
  691. }
  692. }
  693. }
  694. /**
  695. * 因为提交其他数据,引起的树结构数据更新,调用该方法
  696. *
  697. * @param data - 更新的数据 {update, create, delete}
  698. * @param {function} callback - 界面刷新
  699. */
  700. loadPostData(data, callback) {
  701. const result = {}, parents = [];
  702. if (data.update) {
  703. result.update = this._updateData(data.update);
  704. this._getNodesParents(parents, result.update);
  705. }
  706. if (data.create) {
  707. result.create = this._loadData(data.create);
  708. this._getNodesParents(parents, result.create);
  709. }
  710. if (data.delete) {
  711. result.delete = this._freeData(data.delete);
  712. this._getNodesParents(parents, result.delete);
  713. }
  714. parents.sort((a, b) => {
  715. return b.level - a.level;
  716. });
  717. for (const parent of parents) {
  718. treeCalc.calculateNode(this, parent, this.setting.calcFields, this.setting.calcFun);
  719. }
  720. result.update = result.update ? result.update.concat(parents) : parents;
  721. callback(result);
  722. }
  723. /**
  724. * 以下方法需等待响应, 通过callback刷新界面
  725. */
  726. /**
  727. * 加载子节点
  728. * @param {Object} node
  729. * @param {function} callback
  730. */
  731. loadChildren (node, callback) {
  732. const self = this;
  733. const url = this.setting.preUrl ? this.setting.preUrl + '/get-children' : 'get-children';
  734. postData(url, this.getNodeKeyData(node), function (data) {
  735. self._loadData(data);
  736. callback();
  737. });
  738. };
  739. /**
  740. * 树结构基本操作
  741. * @param {String} url - 请求地址
  742. * @param {Object} node - 操作节点
  743. * @param {String} type - 操作类型
  744. * @param {function} callback - 界面刷新
  745. */
  746. baseOperation (url, node, type, callback) {
  747. const self = this;
  748. const data = {
  749. id: node[this.setting.id],
  750. postType: type
  751. };
  752. postData(url, data, function (datas) {
  753. self.loadPostData(datas, callback);
  754. });
  755. };
  756. /**
  757. * 节点数据编辑
  758. * @param {String} url - 请求地址
  759. * @param {Array|Object} updateData - 需更新的数据
  760. * @param {function} callback - 界面刷新
  761. */
  762. update (url, updateData, callback) {
  763. const self = this;
  764. postData(url, updateData, function (datas) {
  765. self.loadPostData(datas, callback);
  766. }, function () {
  767. if (updateData instanceof Array) {
  768. const result = [];
  769. for (const data of updateData) {
  770. result.push(self.getItems(data[self.setting.id]));
  771. }
  772. callback(result)
  773. } else {
  774. callback([self.getItems(updateData[self.setting.id])]);
  775. }
  776. });
  777. };
  778. /**
  779. * 复制粘贴整块(目前仅可粘贴为后项)
  780. * @param {String} url - 请求地址
  781. * @param {Object} node - 操作节点
  782. * @param {Array} block - 被复制整块的节点列表
  783. * @param {function} callback - 界面刷新
  784. */
  785. pasteBlock (url, node, block, callback) {
  786. const self = this;
  787. const data = {
  788. id: node[self.setting.id],
  789. block: block
  790. };
  791. postData(url, data, function (datas) {
  792. self.loadPostData(datas, callback);
  793. });
  794. };
  795. /**
  796. * 提交数据
  797. * @param {String} url - 请求地址
  798. * @param {Object} node - 当前选中节点
  799. * @param {Object} data - 提交的数据
  800. * @param {function} callback - 界面刷新
  801. */
  802. postData (url, node, data, callback) {
  803. const self = this;
  804. if (node) {
  805. data.id = node[self.setting.id];
  806. }
  807. postData(url, data, function (datas) {
  808. const result = {};
  809. if (datas.update) {
  810. result.update = self._updateData(datas.update);
  811. }
  812. if (datas.create) {
  813. result.create = self._loadData(datas.create);
  814. }
  815. if (datas.delete) {
  816. result.delete = self._freeData(datas.delete);
  817. }
  818. if (datas.expand) {
  819. const [create, update] = self._loadExpandData(datas.expand);
  820. result.create = result.create ? result.create.concat(create) : create;
  821. result.expand = update;
  822. }
  823. callback(result);
  824. });
  825. };
  826. }
  827. class StageTree extends FxTree {
  828. /**
  829. * 构造函数
  830. */
  831. constructor (setting) {
  832. super(setting);
  833. // stage关联索引
  834. this.stageItems = {};
  835. }
  836. /**
  837. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  838. * @param datas
  839. */
  840. loadDatas (datas) {
  841. super.loadDatas(datas);
  842. // 清空旧数据
  843. this.stageItems = {};
  844. // 加载全部数据
  845. for (const data of this.datas) {
  846. const keyName = itemsPre + data[this.setting.stageId];
  847. this.stageItems[keyName] = data;
  848. }
  849. }
  850. getStageItems(id) {
  851. return this.stageItems[itemsPre + id];
  852. }
  853. loadStageData(datas, fieldPre, fields) {
  854. datas = datas instanceof Array ? datas : [datas];
  855. const loadedData = [];
  856. for (const data of datas) {
  857. let node = this.getStageItems(data.lid);
  858. if (node) {
  859. for (const prop of fields) {
  860. if (data[fieldPre + prop] !== undefined) {
  861. node[fieldPre + prop] = data[prop];
  862. }
  863. }
  864. loadedData.push(node);
  865. }
  866. }
  867. }
  868. loadPreStageData(preStageData) {
  869. this.loadStageData(curStageData, 'pre_', this.setting.updateFields);
  870. }
  871. loadCurStageData(curStageData) {
  872. this.loadStageData(curStageData, '', this.setting.updateFields);
  873. }
  874. /**
  875. * 加载数据(动态),只加载不同部分
  876. * @param {Array} datas
  877. * @return {Array} 加载到树的数据
  878. * @privateA
  879. */
  880. _updateStageData (datas) {
  881. datas = datas instanceof Array ? datas : [datas];
  882. const loadedData = [];
  883. for (const data of datas) {
  884. let node = this.getStageItems(data.lid);
  885. if (node) {
  886. for (const prop of this.setting.updateFields) {
  887. if (data[prop] !== undefined) {
  888. node[prop] = data[prop];
  889. }
  890. }
  891. loadedData.push(node);
  892. }
  893. }
  894. return loadedData;
  895. };
  896. /**
  897. *
  898. * @param parent
  899. * @param node
  900. * @private
  901. */
  902. _getNodesParents(parents, nodes) {
  903. for (const node of nodes) {
  904. const parent = this.getParent(node);
  905. if (parent) {
  906. const paths = this.getFullPathNodes(parent.full_path);
  907. for (const p of paths) {
  908. if (parents.indexOf(p) === -1) {
  909. parents.push(p);
  910. }
  911. }
  912. }
  913. if (node.children && node.children.length > 0) {
  914. parents.push(node);
  915. }
  916. }
  917. }
  918. /**
  919. * 提交数据至后端,返回的前端树结构应刷新的部分
  920. * StageTree仅有更新CurStage部分,不需要增删
  921. *
  922. * @param data - 需要更新的数据
  923. * @returns {Array} - 界面需要刷新的数据
  924. */
  925. loadPostStageData(data) {
  926. let result, parents = [];
  927. if (data) {
  928. result = this._updateStageData(data);
  929. this._getNodesParents(parents, result);
  930. }
  931. result = result ? result.concat(parents) : parents;
  932. result.sort((a, b) => {
  933. return b.level - a.level;
  934. });
  935. for (const node of result) {
  936. treeCalc.calculateNode(this, node);
  937. }
  938. return result;
  939. }
  940. }
  941. class MasterTree extends FxTree {
  942. /**
  943. * 构造函数
  944. */
  945. constructor (setting) {
  946. super(setting);
  947. // 关联索引
  948. this.masterItems = {};
  949. }
  950. /**
  951. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  952. * @param datas
  953. */
  954. loadDatas (datas) {
  955. super.loadDatas(datas);
  956. // 清空旧数据
  957. this.masterItems = {};
  958. // minor数据缓存
  959. this.minorData = {};
  960. // 加载全部数据
  961. for (const data of this.datas) {
  962. const keyName = itemsPre + data[this.setting.masterId];
  963. this.masterItems[keyName] = data;
  964. }
  965. }
  966. /**
  967. * 根据关联id,查找节点
  968. * @param id
  969. * @returns {*}
  970. */
  971. getMasterItems(id) {
  972. return this.masterItems[itemsPre + id];
  973. }
  974. /**
  975. * 加载关联数据
  976. *
  977. * @param {Array|Object}datas - 需要关联的数据
  978. * @param {String} fieldPre - 关联字段前缀(关联结果)
  979. * @param {Array} fields - 关联字段
  980. * @returns {Array}
  981. */
  982. loadMinorData(datas, fieldSuf, fields) {
  983. if (!datas) { return; }
  984. datas = datas instanceof Array ? datas : [datas];
  985. this.minorData[fieldSuf] = datas;
  986. const loadedData = [];
  987. for (const data of datas) {
  988. let node = this.getMasterItems(data[this.setting.minorId]);
  989. if (node) {
  990. for (const prop of fields) {
  991. if (data[prop] !== undefined) {
  992. node[prop + fieldSuf] = data[prop];
  993. }
  994. }
  995. loadedData.push(node);
  996. }
  997. }
  998. return loadedData;
  999. }
  1000. /**
  1001. * 展开至最底层项目节
  1002. */
  1003. expandByCalcFields() {
  1004. const self = this;
  1005. this.expandByCustom(function (node) {
  1006. for (const field of self.setting.calcFields) {
  1007. if (node[field]) {
  1008. return true;
  1009. }
  1010. }
  1011. return false;
  1012. })
  1013. }
  1014. }
  1015. if (type === 'base') {
  1016. return new BaseTree(setting);
  1017. } else if (type === 'stage') {
  1018. return new StageTree(setting);
  1019. } else if (type === 'ledger') {
  1020. return new LedgerTree(setting);
  1021. } else if (type === 'measure') {
  1022. return new MeasureTree(setting);
  1023. } else if (type === 'master') {
  1024. return new MasterTree(setting);
  1025. }
  1026. };
  1027. const treeCalc = {
  1028. getMaxLevel: function (tree) {
  1029. return Math.max.apply(Math, tree.datas.map(function(o) {return o.level}));
  1030. },
  1031. calculateNode: function (tree, node) {
  1032. if (node.children && node.children.length > 0) {
  1033. const gather = node.children.reduce(function (rst, x) {
  1034. const result = {};
  1035. const fieldCalc = function (field) {
  1036. if (rst[field]) {
  1037. result[field] = x[field] ? _.round(rst[field] + x[field], 6) : rst[field];
  1038. } else {
  1039. result[field] = x[field] ? x[field] : undefined;
  1040. }
  1041. };
  1042. for (const cf of tree.setting.calcFields) {
  1043. result[cf] = _.round(_.add(rst[cf], x[cf]), 8);
  1044. //fieldCalc(cf);
  1045. }
  1046. return result;
  1047. });
  1048. // 汇总子项
  1049. for (const cf of tree.setting.calcFields) {
  1050. //node[cf] = _.sumBy(node.children, cf);
  1051. if (gather[cf]) {
  1052. node[cf] = gather[cf];
  1053. } else {
  1054. node[cf] = null;
  1055. }
  1056. }
  1057. }
  1058. // 自身运算
  1059. if (tree.setting.calcFun) {
  1060. tree.setting.calcFun(node);
  1061. }
  1062. },
  1063. calculateLevelNode: function (tree, level) {
  1064. const nodes = tree.datas.filter((n) => { return n.level === level });
  1065. for (const node of nodes) {
  1066. this.calculateNode(tree, node);
  1067. }
  1068. },
  1069. calculateAll: function (tree) {
  1070. for (let i = this.getMaxLevel(tree); i >= 0; i--) {
  1071. this.calculateLevelNode(tree, i);
  1072. }
  1073. },
  1074. calculateParent: function (tree, node) {
  1075. const nodes = tree.getFullPathNodes(node.full_path);
  1076. nodes.sort((a, b) => {
  1077. return b.level - a.level;
  1078. });
  1079. for (const n of nodes) {
  1080. this.calculateNode(tree, n);
  1081. }
  1082. return nodes;
  1083. }
  1084. };