path_tree.bak2.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /**
  2. * 构建pathTree
  3. * 可动态加载子节点,要求子节点获取接口按/xxx/get-children定义
  4. * @param {Object} setting - 设置
  5. * @returns {PathTree}
  6. */
  7. 'use strict';
  8. const itemsPre = 'id_';
  9. const createNewPathTree = function (type, setting) {
  10. class BaseTree {
  11. /**
  12. * 构造函数
  13. */
  14. constructor (setting) {
  15. // 无索引
  16. this.datas = [];
  17. // 以key为索引
  18. this.items = {};
  19. // 以排序为索引
  20. this.nodes = [];
  21. // 索引
  22. this.children = {};
  23. // 树设置
  24. this.setting = JSON.parse(JSON.stringify(setting));
  25. }
  26. /**
  27. * 树结构根据显示排序
  28. */
  29. sortTreeNode (isResort) {
  30. const self = this;
  31. const addSortNodes = function (nodes) {
  32. if (!nodes) { return }
  33. for (let i = 0; i < nodes.length; i++) {
  34. self.nodes.push(nodes[i]);
  35. nodes[i].index = self.nodes.length - 1;
  36. if (!isResort) {
  37. nodes[i].children = self.getChildren(nodes[i]);
  38. }
  39. addSortNodes(nodes[i].children);
  40. }
  41. };
  42. self.nodes = [];
  43. addSortNodes(this.getChildren(null));
  44. }
  45. /**
  46. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  47. * @param datas
  48. */
  49. loadDatas (datas) {
  50. // 清空旧数据
  51. this.items = {};
  52. this.nodes = [];
  53. // 加载全部数据
  54. for (const data of datas) {
  55. const keyName = itemsPre + data[this.setting.id];
  56. this.items[keyName] = JSON.parse(JSON.stringify(data));
  57. this.datas.push(this.items[keyName]);
  58. }
  59. this.sortTreeNode();
  60. for (const node of this.nodes) {
  61. node.expanded = node.children.length > 0;
  62. node.visible = true;
  63. }
  64. }
  65. /**
  66. * 根据id获取树结构节点数据
  67. * @param {Number} id
  68. * @returns {Object}
  69. */
  70. getItems (id) {
  71. return this.items[itemsPre + id];
  72. };
  73. /**
  74. * 查找node的parent
  75. * @param {Object} node
  76. * @returns {Object}
  77. */
  78. getParent (node) {
  79. return this.getItems(node[this.setting.pid]);
  80. };
  81. /**
  82. * 根据path查找完整节点
  83. * @param {Number} path
  84. */
  85. getFullPathNodes (path) {
  86. const self = this, ids = path.split('.');
  87. if (ids.length > 0) {
  88. return this.nodes.filter((x) => {
  89. return ids.indexOf('' + x[self.setting.id]) >= 0;
  90. });
  91. } else {
  92. return [];
  93. }
  94. };
  95. /**
  96. * 查询node的已下载子节点
  97. * @param {Object} node
  98. * @returns {Array}
  99. */
  100. getChildren (node) {
  101. const setting = this.setting;
  102. const pid = node ? node[setting.id] : setting.rootId;
  103. const children = this.datas.filter(function (x) {
  104. return x[setting.pid] === pid;
  105. });
  106. children.sort(function (a, b) {
  107. return a.order - b.order;
  108. });
  109. return children;
  110. };
  111. /**
  112. * 查询node的已下载的全部后代
  113. * @param {Object} node
  114. * @returns {Array}
  115. */
  116. getPosterity (node) {
  117. const reg = new RegExp('^' + node.full_path + '.');
  118. return this.datas.filter(function (x) {
  119. return reg.test(x.full_path);
  120. })
  121. };
  122. /**
  123. * 查询node是否是父节点的最后一个子节点
  124. * @param {Object} node
  125. * @returns {boolean}
  126. */
  127. isLastSibling (node) {
  128. const siblings = this.getChildren(this.getParent(node));
  129. return node.order === siblings[siblings.length - 1].order;
  130. };
  131. /**
  132. * 刷新子节点是否可见
  133. * @param {Object} node
  134. * @private
  135. */
  136. _refreshChildrenVisible (node) {
  137. if (!node.children) {
  138. node.children = this.getChildren(node);
  139. }
  140. if (node.children && node.children.length > 0) {
  141. for (const child of node.children) {
  142. child.visible = node.expanded && node.visible;
  143. this._refreshChildrenVisible(child);
  144. }
  145. }
  146. };
  147. /**
  148. * 设置节点是否展开, 并控制子节点可见
  149. * @param {Object} node
  150. * @param {Boolean} expanded
  151. */
  152. setExpanded (node, expanded) {
  153. node.expanded = expanded;
  154. this._refreshChildrenVisible(node);
  155. };
  156. /**
  157. * 提取节点key和索引数据
  158. * @param {Object} node - 节点
  159. * @returns {key}
  160. */
  161. getNodeKeyData (node) {
  162. const data = {};
  163. for (const key of this.setting.keys) {
  164. data[key] = node[key];
  165. }
  166. return data;
  167. };
  168. /**
  169. * 得到树结构构成id
  170. * @param node
  171. * @returns {*}
  172. */
  173. getNodeKey (node) {
  174. return node[this.setting.id];
  175. };
  176. }
  177. class MeasureTree extends BaseTree {
  178. addData (datas) {
  179. const loadedData = [];
  180. for (const data of datas) {
  181. let node = this.getItems(data[this.setting.id]);
  182. if (node) {
  183. for (const prop in node) {
  184. if (data[prop] !== undefined) {
  185. node[prop] = data[prop];
  186. }
  187. }
  188. loadedData.push(node);
  189. } else {
  190. const keyName = itemsPre + data[this.setting.id];
  191. const node = JSON.parse(JSON.stringify(data));
  192. this.items[keyName] = node;
  193. this.datas.push(node);
  194. node.expanded = false;
  195. node.visible = true;
  196. loadedData.push(node);
  197. }
  198. }
  199. this.sortTreeNode();
  200. for (const node of loadedData) {
  201. const children = node.children;
  202. if (!node.expanded && children.length > 0) {
  203. node.expanded = true;
  204. this._refreshChildrenVisible(node);
  205. }
  206. }
  207. return loadedData;
  208. }
  209. removeData (datas) {
  210. datas.sort(function (a, b) {
  211. return b.level - a.level;
  212. });
  213. console.log(datas);
  214. const removeArrayData = function (array, data) {
  215. const index = array.indexOf(data);
  216. array.splice(index, 1);
  217. };
  218. for (const data of datas) {
  219. const node = this.getItems(data[this.setting.id]);
  220. if (node && this.getChildren(node).length === 0) {
  221. delete this.items[itemsPre + node[this.setting.id]];
  222. if (node[this.setting.pid] !== this.setting.rootId) {
  223. const parent = this.items[itemsPre + node[this.setting.pid]];
  224. removeArrayData(parent.children, node);
  225. }
  226. removeArrayData(this.datas, node);
  227. removeArrayData(this.nodes, node);
  228. }
  229. }
  230. };
  231. loadLeafData (data) {
  232. const datas = data instanceof Array ? data : [data];
  233. for (const d of datas) {
  234. let node = this.getItems(d[this.setting.id]);
  235. if (node && node.is_leaf) {
  236. for (const prop in node) {
  237. if (data[prop] !== undefined) {
  238. node[prop] = d[prop];
  239. }
  240. }
  241. }
  242. }
  243. };
  244. }
  245. class ActiveTree extends BaseTree {
  246. /**
  247. * 加载数据(动态),只加载不同部分
  248. * @param {Array} datas
  249. * @return {Array} 加载到树的数据
  250. * @privateA
  251. */
  252. _loadData (datas) {
  253. const loadedData = [];
  254. for (const data of datas) {
  255. let node = this.getItems(data[this.setting.id]);
  256. if (node) {
  257. for (const prop in node) {
  258. if (data[prop] !== undefined) {
  259. node[prop] = data[prop];
  260. }
  261. }
  262. loadedData.push(node);
  263. } else {
  264. const keyName = itemsPre + data[this.setting.id];
  265. const node = JSON.parse(JSON.stringify(data));
  266. this.items[keyName] = node;
  267. this.datas.push(node);
  268. node.expanded = false;
  269. node.visible = true;
  270. loadedData.push(node);
  271. }
  272. }
  273. this.sortTreeNode();
  274. for (const node of loadedData) {
  275. const children = node.children;
  276. if (!node.expanded && children.length > 0) {
  277. node.expanded = true;
  278. this._refreshChildrenVisible(node);
  279. }
  280. }
  281. return loadedData;
  282. };
  283. /**
  284. * 以下方法需等待响应, 通过callback刷新界面
  285. */
  286. /**
  287. * 加载子节点
  288. * @param {Object} node
  289. * @param {function} callback
  290. */
  291. loadChildren (node, callback) {
  292. const self = this;
  293. const url = this.setting.preUrl ? this.setting.preUrl + '/get-children' : 'get-children';
  294. console.log(url);
  295. postData(url, this.getNodeKeyData(node), function (data) {
  296. self._loadData(data);
  297. callback();
  298. });
  299. };
  300. }
  301. class LedgerTree extends BaseTree {
  302. /**
  303. * 加载数据(动态),只加载不同部分
  304. * @param {Array} datas
  305. * @return {Array} 加载到树的数据
  306. * @privateA
  307. */
  308. _updateData (datas) {
  309. const loadedData = [];
  310. for (const data of datas) {
  311. let node = this.getItems(data[this.setting.id]);
  312. if (node) {
  313. for (const prop in node) {
  314. if (data[prop] !== undefined) {
  315. node[prop] = data[prop];
  316. }
  317. }
  318. loadedData.push(node);
  319. }
  320. }
  321. for (const node of loadedData) {
  322. const children = this.getChildren(node);
  323. node.expanded = children.length > 0 && children[0].visible;
  324. }
  325. this.sortTreeNode(true);
  326. return loadedData;
  327. };
  328. /**
  329. * 加载数据(动态),只加载不同部分
  330. * @param {Array} datas
  331. * @return {Array} 加载到树的数据
  332. * @privateA
  333. */
  334. _loadData (datas) {
  335. const loadedData = [], resortData = [];
  336. for (const data of datas) {
  337. let node = this.getItems(data[this.setting.id]);
  338. if (node) {
  339. const parent = this.getItems(node[this.setting.pid]);
  340. for (const prop in node) {
  341. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  342. node[prop] = data[prop];
  343. if (parent && resortData.indexOf(parent) === -1) {
  344. resortData.push(parent);
  345. }
  346. }
  347. }
  348. loadedData.push(node);
  349. } else {
  350. const keyName = itemsPre + data[this.setting.id];
  351. const node = JSON.parse(JSON.stringify(data));
  352. this.items[keyName] = node;
  353. this.datas.push(node);
  354. node.expanded = false;
  355. node.visible = true;
  356. loadedData.push(node);
  357. if (resortData.indexOf(node) === -1) {
  358. resortData.push(node);
  359. }
  360. const parent = this.getItems(node[this.setting.pid]);
  361. if (parent && resortData.indexOf(parent) === -1) {
  362. resortData.push(parent);
  363. }
  364. }
  365. }
  366. for (const node of resortData) {
  367. node.children = this.getChildren(node);
  368. }
  369. this.sortTreeNode(true);
  370. for (const node of loadedData) {
  371. if (!node.expanded) {
  372. this.setExpanded(node, true);
  373. }
  374. }
  375. return loadedData;
  376. };
  377. /**
  378. * 清理数据(动态)
  379. * @param datas
  380. * @private
  381. */
  382. _freeData (datas) {
  383. const removeArrayData = function (array, data) {
  384. const index = array.indexOf(data);
  385. array.splice(index, 1);
  386. };
  387. for (const data of datas) {
  388. const node = this.getItems(data[this.setting.id]);
  389. if (node) {
  390. delete this.items[itemsPre + node[this.setting.id]];
  391. if (node[this.setting.pid] !== this.setting.rootId) {
  392. const parent = this.getItems(node[this.setting.pid]);
  393. if (parent) {
  394. removeArrayData(parent.children, node);
  395. }
  396. }
  397. removeArrayData(this.datas, node);
  398. removeArrayData(this.nodes, node);
  399. }
  400. }
  401. };
  402. /**
  403. * 加载需展开的数据
  404. * @param {Array} datas
  405. * @returns {Array}
  406. * @private
  407. */
  408. _loadExpandData (datas) {
  409. const loadedData = [], existData = [], expandData = [], resortData = [];
  410. for (const data of datas) {
  411. let node = this.getItems(data[this.setting.id]);
  412. if (node) {
  413. existData.push(node);
  414. } else {
  415. const keyName = itemsPre + data[this.setting.id];
  416. const node = JSON.parse(JSON.stringify(data));
  417. this.items[keyName] = node;
  418. this.datas.push(node);
  419. node.expanded = false;
  420. node.visible = true;
  421. loadedData.push(node);
  422. if (resortData.indexOf(node) === -1) {
  423. resortData.push(node);
  424. }
  425. const parent = this.getItems(node[this.setting.pid]);
  426. if (parent && resortData.indexOf(parent) === -1) {
  427. resortData.push(parent);
  428. }
  429. }
  430. }
  431. for (const node of resortData) {
  432. node.children = this.getChildren(node);
  433. }
  434. this.sortTreeNode(true);
  435. for (const node of loadedData) {
  436. if (!node.expanded) {
  437. this.setExpanded(node, true);
  438. }
  439. }
  440. for (const node of existData) {
  441. const parent = this.getItems(node[this.setting.pid]);
  442. if (expandData.indexOf(parent) === -1) {
  443. expandData.push(parent);
  444. if (!parent.expanded) {
  445. this.setExpanded(parent, true);
  446. }
  447. }
  448. if (!node.expanded) {
  449. this.setExpanded(node, true);
  450. }
  451. }
  452. return [loadedData, expandData];
  453. };
  454. /**
  455. * 以下方法需等待响应, 通过callback刷新界面
  456. */
  457. /**
  458. * 加载子节点
  459. * @param {Object} node
  460. * @param {function} callback
  461. */
  462. loadChildren (node, callback) {
  463. const self = this;
  464. const url = this.setting.preUrl ? this.setting.preUrl + '/get-children' : 'get-children';
  465. console.log(url);
  466. postData(url, this.getNodeKeyData(node), function (data) {
  467. self._loadData(data);
  468. callback();
  469. });
  470. };
  471. /**
  472. * 树结构基本操作
  473. * @param {String} url - 请求地址
  474. * @param {Object} node - 操作节点
  475. * @param {String} type - 操作类型
  476. * @param {function} callback - 界面刷新
  477. */
  478. baseOperation (url, node, type, callback) {
  479. const self = this;
  480. const data = {
  481. id: node[this.setting.id],
  482. postType: type
  483. };
  484. postData(url, data, function (datas) {
  485. const result = {};
  486. if (datas.update) {
  487. result.update = self._updateData(datas.update);
  488. }
  489. if (datas.create) {
  490. result.create = self._loadData(datas.create);
  491. }
  492. if (datas.delete) {
  493. result.delete = self._freeData(datas.delete);
  494. }
  495. callback(result);
  496. });
  497. };
  498. /**
  499. * 节点数据编辑
  500. * @param {String} url - 请求地址
  501. * @param {Array|Object} updateData - 需更新的数据
  502. * @param {function} callback - 界面刷新
  503. */
  504. update (url, updateData, callback) {
  505. const self = this;
  506. postData(url, updateData, function (datas) {
  507. const result = self._updateData(datas);
  508. callback(result);
  509. }, function () {
  510. if (updateData instanceof Array) {
  511. const result = [];
  512. for (const data of updateData) {
  513. result.push(self.getItems(data[self.setting.id]));
  514. }
  515. callback(result)
  516. } else {
  517. callback([self.getItems(updateData[self.setting.id])]);
  518. }
  519. });
  520. };
  521. /**
  522. * 复制粘贴整块(目前仅可粘贴为后项)
  523. * @param {String} url - 请求地址
  524. * @param {Object} node - 操作节点
  525. * @param {Array} block - 被复制整块的节点列表
  526. * @param {function} callback - 界面刷新
  527. */
  528. pasteBlock (url, node, block, callback) {
  529. const self = this;
  530. const data = {
  531. id: node[self.setting.id],
  532. block: block
  533. };
  534. postData(url, data, function (datas) {
  535. const result = {};
  536. if (datas.update) {
  537. result.update = self._updateData(datas.update);
  538. }
  539. if (datas.create) {
  540. result.create = self._loadData(datas.create);
  541. }
  542. if (datas.delete) {
  543. result.delete = self._freeData(datas.delete);
  544. }
  545. callback(result);
  546. });
  547. };
  548. /**
  549. * 提交数据
  550. * @param {String} url - 请求地址
  551. * @param {Object} node - 当前选中节点
  552. * @param {Object} data - 提交的数据
  553. * @param {function} callback - 界面刷新
  554. */
  555. postData (url, node, data, callback) {
  556. const self = this;
  557. if (node) {
  558. data.id = node[self.setting.id];
  559. }
  560. postData(url, data, function (datas) {
  561. const result = {};
  562. console.log('childrenCount: ' + datas.expand.length);
  563. let time = new Date();
  564. if (datas.update) {
  565. result.update = self._updateData(datas.update);
  566. }
  567. if (datas.create) {
  568. result.create = self._loadData(datas.create);
  569. }
  570. if (datas.delete) {
  571. result.delete = self._freeData(datas.delete);
  572. }
  573. if (datas.expand) {
  574. const [create, update] = self._loadExpandData(datas.expand);
  575. result.create = result.create ? result.create.concat(create) : create;
  576. result.expand = update;
  577. }
  578. time = new Date() - time;
  579. console.log('analysisData: ' + time);
  580. callback(result);
  581. });
  582. };
  583. batchInsert (url, node, data, callback) {
  584. const self = this;
  585. data.id = node[self.setting.id];
  586. postData(url, data, function (datas) {
  587. const result = {};
  588. if (datas.update) {
  589. result.update = self._updateData(datas.update);
  590. }
  591. if (datas.create) {
  592. result.create = self._loadData(datas.create);
  593. }
  594. if (datas.delete) {
  595. result.delete = self._freeData(datas.delete);
  596. }
  597. callback(result);
  598. });
  599. };
  600. }
  601. if (type === 'base') {
  602. return new BaseTree(setting);
  603. } else if (type === 'active') {
  604. return new ActiveTree(setting);
  605. } else if (type === 'ledger') {
  606. return new LedgerTree(setting);
  607. } else if (type === 'measure') {
  608. return new MeasureTree(setting);
  609. }
  610. };
  611. const treeCalc = {
  612. getMaxLevel: function (tree) {
  613. return Math.max.apply(Math, tree.datas.map(function(o) {return o.level}));
  614. },
  615. calculateNode: function (tree, node, calcFields) {
  616. const children = tree.getChildren(node);
  617. if (children.length > 0) {
  618. const gather = children.reduce(function (rst, x) {
  619. const result = {};
  620. const fieldCalc = function (field) {
  621. if (rst[field]) {
  622. result[field] = x[field] ? rst[field] + x[field] : rst[field];
  623. } else {
  624. result[field] = x[field] ? x[field] : undefined;
  625. }
  626. }
  627. for (const cf of calcFields) {
  628. fieldCalc(cf);
  629. }
  630. return result;
  631. });
  632. for (const cf of calcFields) {
  633. if (gather[cf]) {
  634. node[cf] = gather[cf];
  635. }
  636. }
  637. }
  638. },
  639. calculateLevelNode: function (tree, level, calcFields) {
  640. const nodes = tree.datas.filter((n) => { return n.level === level });
  641. for (const node of nodes) {
  642. this.calculateNode(tree, node, calcFields);
  643. }
  644. },
  645. calculateAll: function (tree, calcFields) {
  646. for (let i = this.getMaxLevel(tree); i >= 0; i--) {
  647. this.calculateLevelNode(tree, i, calcFields);
  648. }
  649. },
  650. calculateParent: function (tree, node, calcFields) {
  651. const nodes = tree.getFullPathNodes(node.full_path);
  652. nodes.sort((a, b) => {
  653. return b.level - a.level;
  654. });
  655. for (const n of nodes) {
  656. this.calculateNode(tree, n, calcFields);
  657. }
  658. return nodes;
  659. }
  660. }