path_tree.js 37 KB

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