path_tree.js 30 KB

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