path_tree.js 36 KB

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