path_tree.js 37 KB

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