path_tree.js 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  1. /**
  2. * (需使用 decimal.min.js, zh_calc.js)
  3. *
  4. * 构建pathTree
  5. * 可动态加载子节点,要求子节点获取接口按/xxx/get-children定义
  6. * @param {Object} setting - 设置
  7. * @returns {PathTree}
  8. */
  9. 'use strict';
  10. class PosData {
  11. /**
  12. * 构造函数
  13. * @param {id|Number, masterId|Number} setting
  14. */
  15. constructor (setting) {
  16. // 无索引
  17. this.datas = null;
  18. // 以key为索引
  19. this.items = {};
  20. // 以分类id为索引的有序
  21. this.ledgerPos = {};
  22. // pos设置
  23. this.setting = setting;
  24. }
  25. /**
  26. * 加载部位明细数据
  27. * @param datas
  28. */
  29. loadDatas(datas) {
  30. this.datas = datas;
  31. this.items = {};
  32. this.ledgerPos = {};
  33. for (const data of this.datas) {
  34. const key = itemsPre + data[this.setting.id];
  35. this.items[key] = data;
  36. const masterKey = itemsPre + data[this.setting.ledgerId];
  37. if (!this.ledgerPos[masterKey]) {
  38. this.ledgerPos[masterKey] = [];
  39. }
  40. this.ledgerPos[masterKey].push(data);
  41. }
  42. for (const prop in this.ledgerPos) {
  43. this.resortLedgerPos(this.ledgerPos[prop]);
  44. }
  45. }
  46. /**
  47. * 更新数据
  48. * @param datas
  49. */
  50. updateDatas(data) {
  51. const datas = data instanceof Array ? data : [data];
  52. const result = { create: [], update: [] }, resort = [];
  53. for (const d of datas) {
  54. const key = itemsPre + d[this.setting.id];
  55. if (!this.items[key]) {
  56. this.datas.push(d);
  57. this.items[key] = d;
  58. const masterKey = itemsPre + d[this.setting.ledgerId];
  59. if (!this.ledgerPos[masterKey]) {
  60. this.ledgerPos[masterKey] = [];
  61. }
  62. this.ledgerPos[masterKey].push(d);
  63. result.create.push(d);
  64. } else {
  65. const pos = this.items[key];
  66. for (const prop in d) {
  67. pos[prop] = d[prop];
  68. }
  69. result.update.push(pos);
  70. }
  71. const masterKey = itemsPre + d[this.setting.ledgerId];
  72. if (resort.indexOf(masterKey) === -1) {
  73. resort.push(masterKey);
  74. }
  75. }
  76. for (const s of resort) {
  77. this.resortLedgerPos(this.ledgerPos[s]);
  78. }
  79. return result;
  80. }
  81. /**
  82. * 移除数据
  83. * @param datas
  84. */
  85. removeDatas(data) {
  86. if (!data) { return; }
  87. const datas = data instanceof Array ? data : [data];
  88. for (let i = datas.length - 1; i >= 0; i--) {
  89. const id = datas[i];
  90. const d = this.getPos(id);
  91. this.datas.splice(this.datas.indexOf(d), 1);
  92. const key = itemsPre + d[this.setting.id];
  93. delete this.items[key];
  94. const masterKey = itemsPre + d[this.setting.ledgerId];
  95. const range = this.ledgerPos[masterKey];
  96. range.splice(range.indexOf(d), 1);
  97. if (range.length === 0) {
  98. delete this.ledgerPos[masterKey];
  99. }
  100. }
  101. }
  102. /**
  103. * 移除数据 - 根据分类id
  104. * @param mid
  105. */
  106. removeDatasByMasterId (mid) {
  107. const masterKey = itemsPre + mid;
  108. const range = this.ledgerPos[masterKey];
  109. if (range) {
  110. delete this.ledgerPos[masterKey];
  111. for (const r of range) {
  112. this.datas.splice(this.datas.indexOf(r), 1);
  113. const key = itemsPre + r[this.setting.id];
  114. delete this.items[key];
  115. }
  116. }
  117. }
  118. getPos(id) {
  119. return this.items[itemsPre + id];
  120. }
  121. getLedgerPos(mid) {
  122. return this.ledgerPos[itemsPre + mid];
  123. }
  124. resortLedgerPos(ledgerPos) {
  125. if (ledgerPos instanceof Array) {
  126. ledgerPos.sort(function (a, b) {
  127. return a.porder - b.porder;
  128. })
  129. }
  130. }
  131. /**
  132. * 计算全部
  133. */
  134. calculateAll() {
  135. if (!this.setting.calcFun) { return; }
  136. for (const pos of this.datas) {
  137. this.setting.calcFun(pos);
  138. }
  139. }
  140. }
  141. class StagePosData extends PosData {
  142. loadStageData(datas, fieldPre, fields) {
  143. if (!datas) { return; }
  144. datas = datas instanceof Array ? datas : [datas];
  145. const loadedData = [];
  146. for (const data of datas) {
  147. let node = this.getPos(data.pid);
  148. if (node) {
  149. for (const prop of fields) {
  150. if (data[prop] !== undefined) {
  151. node[fieldPre + prop] = data[prop];
  152. }
  153. }
  154. if (this.setting.calcFun) {
  155. this.setting.calcFun(node);
  156. }
  157. loadedData.push(node);
  158. }
  159. }
  160. }
  161. loadPreStageData(datas) {
  162. this.loadStageData(datas, 'pre_', this.setting.updateFields);
  163. }
  164. loadCurStageData(datas) {
  165. this.loadStageData(datas, '', this.setting.updateFields);
  166. }
  167. }
  168. class MasterPosData extends PosData {
  169. /**
  170. * 构造函数
  171. * @param {id|Number, masterId|Number} setting
  172. */
  173. constructor (setting) {
  174. super(setting);
  175. // 关联索引
  176. this.masterItems = {};
  177. }
  178. /**
  179. * 加载主数据
  180. * @param datas
  181. */
  182. loadDatas (datas) {
  183. super.loadDatas(datas);
  184. // 清空旧数据
  185. this.masterItems = {};
  186. // minor数据缓存
  187. this.minorData = {};
  188. // 加载全部数据
  189. for (const data of this.datas) {
  190. const keyName = itemsPre + data[this.setting.masterId];
  191. this.masterItems[keyName] = data;
  192. }
  193. }
  194. /**
  195. * 根据关联id,查找节点
  196. * @param id
  197. * @returns {*}
  198. */
  199. getMasterItems(id) {
  200. return this.masterItems[itemsPre + id];
  201. }
  202. /**
  203. * 加载关联数据
  204. *
  205. * @param {Array|Object}datas - 需要关联的数据
  206. * @param {String} fieldPre - 关联字段前缀(关联结果)
  207. * @param {Array} fields - 关联字段
  208. * @returns {Array}
  209. */
  210. loadMinorData(datas, fieldSuf, fields) {
  211. if (!datas) return;
  212. datas = datas instanceof Array ? datas : [datas];
  213. this.minorData[fieldSuf] = datas;
  214. const loadedData = [];
  215. for (const data of datas) {
  216. let node = this.getMasterItems(data[this.setting.minorId]);
  217. if (node) {
  218. for (const prop of fields) {
  219. if (data[prop] !== undefined) {
  220. node[prop + fieldSuf] = data[prop];
  221. }
  222. }
  223. loadedData.push(node);
  224. }
  225. }
  226. return loadedData;
  227. }
  228. }
  229. const itemsPre = 'id_';
  230. const createNewPathTree = function (type, setting) {
  231. class BaseTree {
  232. /**
  233. * 构造函数
  234. */
  235. constructor (setting) {
  236. // 无索引
  237. this.datas = [];
  238. // 以key为索引
  239. this.items = {};
  240. // 以排序为索引
  241. this.nodes = [];
  242. // 根节点
  243. this.children = [];
  244. // 树设置
  245. this.setting = setting;
  246. }
  247. /**
  248. * 树结构根据显示排序
  249. */
  250. sortTreeNode (isResort) {
  251. const self = this;
  252. const addSortNodes = function (nodes) {
  253. if (!nodes) { return }
  254. for (let i = 0; i < nodes.length; i++) {
  255. self.nodes.push(nodes[i]);
  256. nodes[i].index = self.nodes.length - 1;
  257. if (!isResort) {
  258. nodes[i].children = self.getChildren(nodes[i]);
  259. } else {
  260. nodes[i].children.sort(function (a, b) {
  261. return a.order - b.order;
  262. })
  263. }
  264. addSortNodes(nodes[i].children);
  265. }
  266. };
  267. this.nodes = [];
  268. addSortNodes(this.children);
  269. }
  270. /**
  271. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  272. * @param datas
  273. */
  274. loadDatas (datas) {
  275. // 清空旧数据
  276. this.items = {};
  277. this.nodes = [];
  278. this.datas = [];
  279. this.children = [];
  280. // 加载全部数据
  281. datas.sort(function (a, b) {
  282. return a.level - b.level;
  283. });
  284. for (const data of datas) {
  285. const keyName = itemsPre + data[this.setting.id];
  286. if (!this.items[keyName]) {
  287. const item = JSON.parse(JSON.stringify(data));
  288. item.children = [];
  289. item.expanded = true;
  290. item.visible = true;
  291. this.items[keyName] = item;
  292. this.datas.push(item);
  293. if (item[setting.pid] === setting.rootId) {
  294. this.children.push(item);
  295. } else {
  296. const parent = this.getParent(item);
  297. if (parent) {
  298. parent.children.push(item);
  299. }
  300. }
  301. }
  302. }
  303. this.children.sort(function (a, b) {
  304. return a.order - b.order;
  305. });
  306. this.sortTreeNode(true);
  307. }
  308. getItemsByIndex(index) {
  309. return this.nodes[index];
  310. }
  311. /**
  312. * 根据id获取树结构节点数据
  313. * @param {Number} id
  314. * @returns {Object}
  315. */
  316. getItems (id) {
  317. return this.items[itemsPre + id];
  318. };
  319. /**
  320. * 查找node的parent
  321. * @param {Object} node
  322. * @returns {Object}
  323. */
  324. getParent (node) {
  325. return this.getItems(node[this.setting.pid]);
  326. };
  327. getAllParents (node) {
  328. const parents = [];
  329. if (node.full_path && node.full_path !== '') {
  330. const parentIds = node.full_path.split('-');
  331. for (const id of parentIds) {
  332. if (id !== node[this.setting.id]) {
  333. parents.push(this.getItems(id));
  334. }
  335. }
  336. } else {
  337. let vP = this.getParent(node);
  338. while (vP) {
  339. parents.push(vP);
  340. vP = this.getParent(vP);
  341. }
  342. }
  343. return parents;
  344. }
  345. /**
  346. * 查找node的前兄弟节点
  347. * @param node
  348. * @returns {*}
  349. */
  350. getPreSiblingNode(node) {
  351. if (!node) return null;
  352. const parent = this.getParent(node);
  353. const siblings = parent ? parent.children : this.children;
  354. const index = siblings.indexOf(node);
  355. return (index > 0) ? siblings[index - 1] : null;
  356. }
  357. /**
  358. * 查找node的后兄弟节点
  359. * @param node
  360. * @returns {*}
  361. */
  362. getNextSiblingNode(node) {
  363. const parent = this.getParent(node);
  364. const siblings = parent ? parent.children : this.children;
  365. const index = siblings.indexOf(node);
  366. if (index >= 0 && index < siblings.length - 1) {
  367. return siblings[index + 1];
  368. } else {
  369. return null;
  370. }
  371. }
  372. /**
  373. * 根据path查找完整节点
  374. * @param {Number} path
  375. */
  376. getFullPathNodes (path) {
  377. const self = this, ids = path.split('-');
  378. if (ids.length > 0) {
  379. return this.nodes.filter((x) => {
  380. return ids.indexOf('' + x[self.setting.id]) >= 0;
  381. });
  382. } else {
  383. return [];
  384. }
  385. };
  386. /**
  387. * 查询node的已下载子节点
  388. * @param {Object} node
  389. * @returns {Array}
  390. */
  391. getChildren (node) {
  392. const setting = this.setting;
  393. const pid = node ? node[setting.id] : setting.rootId;
  394. const children = this.datas.filter(function (x) {
  395. return x[setting.pid] === pid;
  396. });
  397. children.sort(function (a, b) {
  398. return a.order - b.order;
  399. });
  400. return children;
  401. };
  402. /**
  403. * 递归方式 查询node的已下载的全部后代 (兼容full_path不存在的情况)
  404. * @param node
  405. * @returns {*}
  406. * @private
  407. */
  408. _recursiveGetPosterity (node) {
  409. let posterity = node.children;
  410. for (const c of node.children) {
  411. posterity = posterity.concat(this._recursiveGetPosterity(c));
  412. }
  413. return posterity;
  414. };
  415. /**
  416. * 查询node的已下载的全部后代
  417. * @param {Object} node
  418. * @returns {Array}
  419. */
  420. getPosterity (node) {
  421. if (node.full_path !== '') {
  422. const reg = new RegExp('^' + node.full_path + '-');
  423. console.log(reg);
  424. return this.datas.filter(function (x) {
  425. return reg.test(x.full_path);
  426. });
  427. } else {
  428. return this._recursiveGetPosterity(node);
  429. }
  430. };
  431. /**
  432. * 查询node是否是父节点的最后一个子节点
  433. * @param {Object} node
  434. * @returns {boolean}
  435. */
  436. isLastSibling (node) {
  437. const siblings = this.getChildren(this.getParent(node));
  438. return node.order === siblings[siblings.length - 1].order;
  439. };
  440. /**
  441. * 刷新子节点是否可见
  442. * @param {Object} node
  443. * @private
  444. */
  445. _refreshChildrenVisible (node) {
  446. if (!node.children) {
  447. node.children = this.getChildren(node);
  448. }
  449. if (node.children && node.children.length > 0) {
  450. for (const child of node.children) {
  451. child.visible = node.expanded && node.visible;
  452. this._refreshChildrenVisible(child);
  453. }
  454. }
  455. };
  456. /**
  457. * 设置节点是否展开, 并控制子节点可见
  458. * @param {Object} node
  459. * @param {Boolean} expanded
  460. */
  461. setExpanded (node, expanded) {
  462. node.expanded = expanded;
  463. this._refreshChildrenVisible(node);
  464. };
  465. /**
  466. * 提取节点key和索引数据
  467. * @param {Object} node - 节点
  468. * @returns {key}
  469. */
  470. getNodeKeyData (node) {
  471. const data = {};
  472. for (const key of this.setting.keys) {
  473. data[key] = node[key];
  474. }
  475. return data;
  476. };
  477. /**
  478. * 得到树结构构成id
  479. * @param node
  480. * @returns {*}
  481. */
  482. getNodeKey (node) {
  483. return node[this.setting.id];
  484. };
  485. /**
  486. * 递归 设置节点展开状态
  487. * @param {Array} nodes - 需要设置状态的节点
  488. * @param {Object} parent - nodes的父节点
  489. * @param {Function} checkFun - 判断节点展开状态的方法
  490. * @private
  491. */
  492. _recursiveExpand(nodes, parent, checkFun) {
  493. for (const node of nodes) {
  494. node.expanded = checkFun(node);
  495. node.visible = parent ? (parent.expanded && parent.visible) : true;
  496. this._recursiveExpand(node.children, node, checkFun);
  497. }
  498. }
  499. /**
  500. * 自定义展开规则
  501. * @param checkFun
  502. */
  503. expandByCustom(checkFun) {
  504. this._recursiveExpand(this.children, null, checkFun);
  505. }
  506. /**
  507. * 展开到第几层
  508. * @param {Number} level - 展开层数
  509. */
  510. expandByLevel(level) {
  511. // function recursiveExpand(nodes, parent) {
  512. // for (const node of nodes) {
  513. // node.expanded = node.level < level;
  514. // node.visible = parent ? (parent.expanded && parent.visible) : true;
  515. // recursiveExpand(node.children, node);
  516. // }
  517. // }
  518. // recursiveExpand(this.children);
  519. this.expandByCustom(function (n) {
  520. return n.level < level;
  521. });
  522. }
  523. /**
  524. * 自动展开节点node
  525. * @param node
  526. * @returns {*}
  527. */
  528. autoExpandNode(node) {
  529. const parents = this.getAllParents(node);
  530. const reload = [];
  531. for (const p of parents) {
  532. if (!p.expanded) {
  533. reload.push(p);
  534. this.setExpanded(p, true);
  535. }
  536. }
  537. return reload;
  538. }
  539. }
  540. class MeasureTree extends BaseTree {
  541. addData (datas) {
  542. const loadedData = [];
  543. for (const data of datas) {
  544. let node = this.getItems(data[this.setting.id]);
  545. if (node) {
  546. for (const prop in node) {
  547. if (data[prop] !== undefined) {
  548. node[prop] = data[prop];
  549. }
  550. }
  551. loadedData.push(node);
  552. } else {
  553. const keyName = itemsPre + data[this.setting.id];
  554. const node = JSON.parse(JSON.stringify(data));
  555. this.items[keyName] = node;
  556. this.datas.push(node);
  557. node.expanded = false;
  558. node.visible = true;
  559. loadedData.push(node);
  560. }
  561. }
  562. this.sortTreeNode();
  563. for (const node of loadedData) {
  564. const children = node.children;
  565. if (!node.expanded && children.length > 0) {
  566. node.expanded = true;
  567. this._refreshChildrenVisible(node);
  568. }
  569. }
  570. return loadedData;
  571. }
  572. removeData (datas) {
  573. datas.sort(function (a, b) {
  574. return b.level - a.level;
  575. });
  576. const removeArrayData = function (array, data) {
  577. const index = array.indexOf(data);
  578. array.splice(index, 1);
  579. };
  580. for (const data of datas) {
  581. const node = this.getItems(data[this.setting.id]);
  582. if (node && this.getChildren(node).length === 0) {
  583. delete this.items[itemsPre + node[this.setting.id]];
  584. if (node[this.setting.pid] !== this.setting.rootId) {
  585. const parent = this.items[itemsPre + node[this.setting.pid]];
  586. removeArrayData(parent.children, node);
  587. }
  588. removeArrayData(this.datas, node);
  589. removeArrayData(this.nodes, node);
  590. }
  591. }
  592. };
  593. loadLeafData (data) {
  594. const datas = data instanceof Array ? data : [data];
  595. for (const d of datas) {
  596. let node = this.getItems(d[this.setting.id]);
  597. if (node && node.is_leaf) {
  598. for (const prop in node) {
  599. if (data[prop] !== undefined) {
  600. node[prop] = d[prop];
  601. }
  602. }
  603. }
  604. }
  605. };
  606. }
  607. class FxTree extends BaseTree {
  608. /**
  609. * 检查节点是否是最底层项目节
  610. * @param node
  611. * @returns {boolean}
  612. */
  613. isLeafXmj(node) {
  614. if (!node.code) {
  615. return false;
  616. }
  617. for (const child of node.children) {
  618. if (!child.b_code || child.b_code === '') {
  619. return false;
  620. }
  621. }
  622. return true;
  623. }
  624. /**
  625. * 查询最底层项目节(本身或父项)
  626. * @param {Object} node - 查询节点
  627. * @returns {Object}
  628. */
  629. getLeafXmjParent(node) {
  630. let parent = node;
  631. while (parent) {
  632. if (this.isLeafXmj(parent)) {
  633. return parent;
  634. } else {
  635. parent = this.getParent(parent);
  636. }
  637. }
  638. return null;
  639. }
  640. /**
  641. * 展开至最底层项目节
  642. */
  643. expandToLeafXmj() {
  644. const self = this;
  645. this.expandByCustom(function (node) {
  646. if (node.b_code && node.b_code !== '') {
  647. return false;
  648. } else {
  649. return !self.isLeafXmj(node);
  650. }
  651. })
  652. }
  653. /**
  654. * 展开至计算项
  655. */
  656. expandByCalcFields() {
  657. const self = this;
  658. this.expandByCustom(function (node) {
  659. for (const field of self.setting.calcFields) {
  660. if (node[field]) {
  661. return true;
  662. }
  663. }
  664. return false;
  665. })
  666. }
  667. }
  668. class LedgerTree extends FxTree {
  669. /**
  670. * 加载数据(动态),只加载不同部分
  671. * @param {Array} datas
  672. * @return {Array} 加载到树的数据
  673. * @privateA
  674. */
  675. _updateData (datas) {
  676. datas = datas instanceof Array ? datas : [datas];
  677. let loadedData = [];
  678. for (const data of datas) {
  679. let node = this.getItems(data[this.setting.id]);
  680. if (node) {
  681. for (const prop in node) {
  682. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  683. if (prop === this.setting.pid) {
  684. loadedData.push(this.getItems(node[this.setting.pid]));
  685. loadedData.push(this.getItems(data[this.setting.pid]));
  686. }
  687. if (prop === this.setting.order) {
  688. loadedData = loadedData.concat(this.getPosterity(node));
  689. }
  690. node[prop] = data[prop];
  691. }
  692. }
  693. loadedData.push(node);
  694. }
  695. }
  696. loadedData = _.uniq(loadedData);
  697. for (const node of loadedData) {
  698. node.children = this.getChildren(node);
  699. node.expanded = node.children.length === 0 ? true : node.children[0].visible;
  700. }
  701. this.sortTreeNode(true);
  702. return loadedData;
  703. };
  704. /**
  705. * 加载数据(动态),只加载不同部分
  706. * @param {Array} datas
  707. * @return {Array} 加载到树的数据
  708. * @privateA
  709. */
  710. _loadData (datas) {
  711. datas = datas instanceof Array ? datas : [datas];
  712. const loadedData = [], resortData = [];
  713. for (const data of datas) {
  714. let node = this.getItems(data[this.setting.id]);
  715. if (node) {
  716. const parent = this.getItems(node[this.setting.pid]);
  717. for (const prop in node) {
  718. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  719. node[prop] = data[prop];
  720. if (parent && resortData.indexOf(parent) === -1) {
  721. resortData.push(parent);
  722. }
  723. }
  724. }
  725. loadedData.push(node);
  726. } else {
  727. const keyName = itemsPre + data[this.setting.id];
  728. const node = JSON.parse(JSON.stringify(data));
  729. this.items[keyName] = node;
  730. this.datas.push(node);
  731. node.expanded = true;
  732. node.visible = true;
  733. loadedData.push(node);
  734. if (resortData.indexOf(node) === -1) {
  735. resortData.push(node);
  736. }
  737. const parent = this.getItems(node[this.setting.pid]);
  738. if (parent && resortData.indexOf(parent) === -1) {
  739. resortData.push(parent);
  740. }
  741. }
  742. }
  743. for (const node of resortData) {
  744. node.children = this.getChildren(node);
  745. }
  746. this.sortTreeNode(true);
  747. for (const node of loadedData) {
  748. if (!node.expanded) {
  749. this.setExpanded(node, true);
  750. }
  751. }
  752. return loadedData;
  753. };
  754. /**
  755. * 清理数据(动态)
  756. * @param datas
  757. * @private
  758. */
  759. _freeData (datas) {
  760. datas = datas instanceof Array ? datas : [datas];
  761. const freeDatas = [];
  762. const removeArrayData = function (array, data) {
  763. const index = array.indexOf(data);
  764. array.splice(index, 1);
  765. };
  766. for (const data of datas) {
  767. const node = this.getItems(data[this.setting.id]);
  768. if (node) {
  769. freeDatas.push(node);
  770. delete this.items[itemsPre + node[this.setting.id]];
  771. if (node[this.setting.pid] !== this.setting.rootId) {
  772. const parent = this.getItems(node[this.setting.pid]);
  773. if (parent) {
  774. removeArrayData(parent.children, node);
  775. }
  776. }
  777. removeArrayData(this.datas, node);
  778. removeArrayData(this.nodes, node);
  779. }
  780. }
  781. return freeDatas;
  782. };
  783. /**
  784. * 加载需展开的数据
  785. * @param {Array} datas
  786. * @returns {Array}
  787. * @private
  788. */
  789. _loadExpandData (datas) {
  790. datas = datas instanceof Array ? datas : [datas];
  791. const loadedData = [], existData = [], expandData = [], resortData = [];
  792. for (const data of datas) {
  793. let node = this.getItems(data[this.setting.id]);
  794. if (node) {
  795. existData.push(node);
  796. } else {
  797. const keyName = itemsPre + data[this.setting.id];
  798. const node = JSON.parse(JSON.stringify(data));
  799. this.items[keyName] = node;
  800. this.datas.push(node);
  801. node.expanded = false;
  802. node.visible = true;
  803. loadedData.push(node);
  804. if (resortData.indexOf(node) === -1) {
  805. resortData.push(node);
  806. }
  807. const parent = this.getItems(node[this.setting.pid]);
  808. if (parent && resortData.indexOf(parent) === -1) {
  809. resortData.push(parent);
  810. }
  811. }
  812. }
  813. for (const node of resortData) {
  814. node.children = this.getChildren(node);
  815. }
  816. this.sortTreeNode(true);
  817. for (const node of loadedData) {
  818. if (!node.expanded) {
  819. this.setExpanded(node, true);
  820. }
  821. }
  822. for (const node of existData) {
  823. const parent = this.getItems(node[this.setting.pid]);
  824. if (expandData.indexOf(parent) === -1) {
  825. expandData.push(parent);
  826. if (!parent.expanded) {
  827. this.setExpanded(parent, true);
  828. }
  829. }
  830. if (!node.expanded) {
  831. this.setExpanded(node, true);
  832. }
  833. }
  834. return [loadedData, expandData];
  835. };
  836. /**
  837. *
  838. * @param parent
  839. * @param node
  840. * @private
  841. */
  842. _getNodesParents(parents, nodes) {
  843. for (const node of nodes) {
  844. const parent = this.getParent(node);
  845. if (parent) {
  846. const paths = this.getFullPathNodes(parent.full_path);
  847. for (const p of paths) {
  848. if (parents.indexOf(p) === -1) {
  849. parents.push(p);
  850. }
  851. }
  852. }
  853. if (this.getItems(node.ledger_id) && node.children.length > 0) {
  854. parents.push(node);
  855. }
  856. }
  857. }
  858. _getReCalcNodes(reCalcNodes, nodes) {
  859. for (const node of nodes) {
  860. const parent = this.getParent(node);
  861. if (parent) {
  862. const paths = this.getFullPathNodes(parent.full_path);
  863. for (const p of paths) {
  864. if (reCalcNodes.indexOf(p) === -1) {
  865. reCalcNodes.push(p);
  866. }
  867. }
  868. }
  869. // 最底层项目节,也需要计算
  870. //if (this.getItems(node.ledger_id) && node.children.length > 0) {
  871. reCalcNodes.push(node);
  872. //}
  873. }
  874. }
  875. /**
  876. * 因为提交其他数据,引起的树结构数据更新,调用该方法
  877. *
  878. * @param data - 更新的数据 {update, create, delete}
  879. * @returns {{}}
  880. */
  881. loadPostData(data) {
  882. const result = {}, reCalcNodes = [];
  883. if (data.update) {
  884. result.update = this._updateData(data.update);
  885. this._getReCalcNodes(reCalcNodes, result.update);
  886. }
  887. if (data.create) {
  888. result.create = this._loadData(data.create);
  889. this._getReCalcNodes(reCalcNodes, result.create);
  890. }
  891. if (data.delete) {
  892. result.delete = this._freeData(data.delete);
  893. this._getReCalcNodes(reCalcNodes, result.delete);
  894. }
  895. reCalcNodes.sort((a, b) => {
  896. return b.level - a.level;
  897. });
  898. for (const node of reCalcNodes) {
  899. treeCalc.calculateNode(this, node, this.setting.calcFields, this.setting.calcFun);
  900. }
  901. result.update = result.update ? result.update.concat(reCalcNodes) : reCalcNodes;
  902. return result;
  903. }
  904. /**
  905. * 以下方法需等待响应, 通过callback刷新界面
  906. */
  907. /**
  908. * 加载子节点
  909. * @param {Object} node
  910. * @param {function} callback
  911. */
  912. loadChildren (node, callback) {
  913. const self = this;
  914. const url = this.setting.preUrl ? this.setting.preUrl + '/get-children' : 'get-children';
  915. postData(url, this.getNodeKeyData(node), function (data) {
  916. self._loadData(data);
  917. callback();
  918. });
  919. };
  920. /**
  921. * 树结构基本操作
  922. * @param {String} url - 请求地址
  923. * @param {Object} node - 操作节点
  924. * @param {String} type - 操作类型
  925. * @param {function} callback - 界面刷新
  926. */
  927. baseOperation (url, node, type, callback) {
  928. const self = this;
  929. const data = {
  930. id: node[this.setting.id],
  931. postType: type
  932. };
  933. postData(url, data, function (datas) {
  934. const refreshData = self.loadPostData(datas);
  935. callback(refreshData);
  936. });
  937. };
  938. /**
  939. * 节点数据编辑
  940. * @param {String} url - 请求地址
  941. * @param {Array|Object} updateData - 需更新的数据
  942. * @param {function} callback - 界面刷新
  943. */
  944. update (url, updateData, callback) {
  945. const self = this;
  946. postData(url, updateData, function (datas) {
  947. const refreshData = self.loadPostData(datas);
  948. callback(refreshData);
  949. }, function () {
  950. if (updateData instanceof Array) {
  951. const result = [];
  952. for (const data of updateData) {
  953. result.push(self.getItems(data[self.setting.id]));
  954. }
  955. callback(result)
  956. } else {
  957. callback([self.getItems(updateData[self.setting.id])]);
  958. }
  959. });
  960. };
  961. /**
  962. * 复制粘贴整块(目前仅可粘贴为后项)
  963. * @param {String} url - 请求地址
  964. * @param {Object} node - 操作节点
  965. * @param {Array} block - 被复制整块的节点列表
  966. * @param {function} callback - 界面刷新
  967. */
  968. pasteBlock (url, node, block, callback) {
  969. const self = this;
  970. const data = {
  971. id: node[self.setting.id],
  972. block: block
  973. };
  974. postData(url, data, function (datas) {
  975. const refreshData = self.loadPostData(datas);
  976. callback(refreshData);
  977. });
  978. };
  979. /**
  980. * 提交数据
  981. * @param {String} url - 请求地址
  982. * @param {Object} node - 当前选中节点
  983. * @param {Object} data - 提交的数据
  984. * @param {function} callback - 界面刷新
  985. */
  986. postData (url, node, data, callback) {
  987. const self = this;
  988. if (node) {
  989. data.id = node[self.setting.id];
  990. }
  991. postData(url, data, function (datas) {
  992. const refreshData = self.loadPostData(datas);
  993. callback(refreshData);
  994. // const result = {};
  995. // if (datas.update) {
  996. // result.update = self._updateData(datas.update);
  997. // }
  998. // if (datas.create) {
  999. // result.create = self._loadData(datas.create);
  1000. // }
  1001. // if (datas.delete) {
  1002. // result.delete = self._freeData(datas.delete);
  1003. // }
  1004. // if (datas.expand) {
  1005. // const [create, update] = self._loadExpandData(datas.expand);
  1006. // result.create = result.create ? result.create.concat(create) : create;
  1007. // result.expand = update;
  1008. // }
  1009. // callback(result);
  1010. });
  1011. };
  1012. }
  1013. class StageTree extends FxTree {
  1014. /**
  1015. * 构造函数
  1016. */
  1017. constructor (setting) {
  1018. super(setting);
  1019. // stage关联索引
  1020. this.stageItems = {};
  1021. }
  1022. /**
  1023. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  1024. * @param datas
  1025. */
  1026. loadDatas (datas) {
  1027. super.loadDatas(datas);
  1028. // 清空旧数据
  1029. this.stageItems = {};
  1030. // 加载全部数据
  1031. for (const data of this.datas) {
  1032. const keyName = itemsPre + data[this.setting.stageId];
  1033. this.stageItems[keyName] = data;
  1034. }
  1035. }
  1036. getStageItems(id) {
  1037. return this.stageItems[itemsPre + id];
  1038. }
  1039. loadStageData(datas, fieldPre, fields) {
  1040. datas = datas instanceof Array ? datas : [datas];
  1041. const loadedData = [];
  1042. for (const data of datas) {
  1043. let node = this.getStageItems(data.lid);
  1044. if (node) {
  1045. for (const prop of fields) {
  1046. if (data[prop] !== undefined) {
  1047. node[fieldPre + prop] = data[prop];
  1048. }
  1049. }
  1050. loadedData.push(node);
  1051. }
  1052. }
  1053. }
  1054. loadPreStageData(datas) {
  1055. this.loadStageData(datas, 'pre_', this.setting.updateFields);
  1056. }
  1057. loadCurStageData(datas) {
  1058. this.loadStageData(datas, '', this.setting.updateFields);
  1059. }
  1060. /**
  1061. * 加载数据(动态),只加载不同部分
  1062. * @param {Array} datas
  1063. * @return {Array} 加载到树的数据
  1064. * @privateA
  1065. */
  1066. _updateData (datas) {
  1067. datas = datas instanceof Array ? datas : [datas];
  1068. let loadedData = [];
  1069. for (const data of datas) {
  1070. let node = this.getItems(data[this.setting.id]);
  1071. if (node) {
  1072. for (const prop in node) {
  1073. if (prop === this.setting.pid && data[prop] !== node[prop]) {
  1074. }
  1075. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  1076. if (prop === this.setting.pid) {
  1077. loadedData.push(this.getItems(node[this.setting.pid]));
  1078. loadedData.push(this.getItems(data[this.setting.pid]));
  1079. }
  1080. node[prop] = data[prop];
  1081. }
  1082. }
  1083. loadedData.push(node);
  1084. }
  1085. }
  1086. loadedData = _.uniq(loadedData);
  1087. for (const node of loadedData) {
  1088. node.children = this.getChildren(node);
  1089. node.expanded = node.children.length === 0 ? true : node.children[0].visible;
  1090. }
  1091. this.sortTreeNode(true);
  1092. return loadedData;
  1093. };
  1094. /**
  1095. * 加载数据(动态),只加载不同部分
  1096. * @param {Array} datas
  1097. * @return {Array} 加载到树的数据
  1098. * @privateA
  1099. */
  1100. _updateStageData (datas) {
  1101. datas = datas instanceof Array ? datas : [datas];
  1102. const loadedData = [];
  1103. for (const data of datas) {
  1104. let node = this.getStageItems(data.lid);
  1105. if (node) {
  1106. for (const prop of this.setting.updateFields) {
  1107. if (data[prop] !== undefined) {
  1108. node[prop] = data[prop];
  1109. }
  1110. }
  1111. loadedData.push(node);
  1112. }
  1113. }
  1114. return loadedData;
  1115. };
  1116. /**
  1117. *
  1118. * @param parent
  1119. * @param node
  1120. * @private
  1121. */
  1122. _getNodesParents(parents, nodes) {
  1123. for (const node of nodes) {
  1124. const parent = this.getParent(node);
  1125. if (parent) {
  1126. const paths = this.getFullPathNodes(parent.full_path);
  1127. for (const p of paths) {
  1128. if (parents.indexOf(p) === -1) {
  1129. parents.push(p);
  1130. }
  1131. }
  1132. }
  1133. if (node.children && node.children.length > 0) {
  1134. parents.push(node);
  1135. }
  1136. }
  1137. }
  1138. _updateDgnData(datas) {
  1139. datas = datas instanceof Array ? datas : [datas];
  1140. let loadedData = [];
  1141. for (const data of datas) {
  1142. let node = this.getStageItems(data.id);
  1143. if (node) {
  1144. for (const prop in data) {
  1145. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  1146. node[prop] = data[prop];
  1147. }
  1148. }
  1149. loadedData.push(node);
  1150. }
  1151. }
  1152. return loadedData;
  1153. }
  1154. /**
  1155. * 提交数据至后端,返回的前端树结构应刷新的部分
  1156. * StageTree仅有更新CurStage部分,不需要增删
  1157. *
  1158. * @param data - 需要更新的数据
  1159. * @returns {Array} - 界面需要刷新的数据
  1160. */
  1161. loadPostStageData(data) {
  1162. let result, parents = [];
  1163. if (data.bills) {
  1164. result = this._updateData(data.bills);
  1165. this._getNodesParents(parents, result);
  1166. }
  1167. if (data.curStageData) {
  1168. result = this._updateStageData(data.curStageData);
  1169. this._getNodesParents(parents, result);
  1170. }
  1171. if (data.dgn) {
  1172. const dgnResult = this._updateDgnData(data.dgn);
  1173. result = result ? result.concat(dgnResult) : dgnResult;
  1174. }
  1175. result = result ? result.concat(parents) : parents;
  1176. result.sort((a, b) => {
  1177. return b.level - a.level;
  1178. });
  1179. for (const node of result) {
  1180. treeCalc.calculateNode(this, node);
  1181. }
  1182. return result;
  1183. }
  1184. }
  1185. class MasterTree extends FxTree {
  1186. /**
  1187. * 构造函数
  1188. */
  1189. constructor (setting) {
  1190. super(setting);
  1191. // 关联索引
  1192. this.masterItems = {};
  1193. }
  1194. /**
  1195. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  1196. * @param datas
  1197. */
  1198. loadDatas (datas) {
  1199. super.loadDatas(datas);
  1200. // 清空旧数据
  1201. this.masterItems = {};
  1202. // minor数据缓存
  1203. this.minorData = {};
  1204. // 加载全部数据
  1205. for (const data of this.datas) {
  1206. const keyName = itemsPre + data[this.setting.masterId];
  1207. this.masterItems[keyName] = data;
  1208. }
  1209. }
  1210. /**
  1211. * 根据关联id,查找节点
  1212. * @param id
  1213. * @returns {*}
  1214. */
  1215. getMasterItems(id) {
  1216. return this.masterItems[itemsPre + id];
  1217. }
  1218. /**
  1219. * 加载关联数据
  1220. *
  1221. * @param {Array|Object}datas - 需要关联的数据
  1222. * @param {String} fieldPre - 关联字段前缀(关联结果)
  1223. * @param {Array} fields - 关联字段
  1224. * @returns {Array}
  1225. */
  1226. loadMinorData(datas, fieldSuf, fields, calcFields) {
  1227. for (const cf of calcFields) {
  1228. this.setting.calcFields.push(cf+fieldSuf);
  1229. }
  1230. if (!datas) return;
  1231. datas = datas instanceof Array ? datas : [datas];
  1232. this.minorData[fieldSuf] = datas;
  1233. const loadedData = [];
  1234. for (const data of datas) {
  1235. let node = this.getMasterItems(data[this.setting.minorId]);
  1236. if (node) {
  1237. for (const prop of fields) {
  1238. if (data[prop] !== undefined) {
  1239. node[prop + fieldSuf] = data[prop];
  1240. }
  1241. }
  1242. loadedData.push(node);
  1243. }
  1244. }
  1245. return loadedData;
  1246. }
  1247. }
  1248. if (type === 'base') {
  1249. return new BaseTree(setting);
  1250. } else if (type === 'fx') {
  1251. return new FxTree(setting);
  1252. } else if (type === 'stage') {
  1253. return new StageTree(setting);
  1254. } else if (type === 'ledger') {
  1255. return new LedgerTree(setting);
  1256. } else if (type === 'measure') {
  1257. return new MeasureTree(setting);
  1258. } else if (type === 'master') {
  1259. return new MasterTree(setting);
  1260. }
  1261. };
  1262. const treeCalc = {
  1263. mapTreeNode: function (tree) {
  1264. let map = {}, maxLevel = 0;
  1265. for (const node of tree.nodes) {
  1266. let levelArr = map[node.level];
  1267. if (!levelArr) {
  1268. levelArr = [];
  1269. map[node.level] = levelArr;
  1270. }
  1271. if (node.level > maxLevel) {
  1272. maxLevel = node.level;
  1273. }
  1274. levelArr.push(node);
  1275. }
  1276. return [maxLevel, map];
  1277. },
  1278. getMaxLevel: function (tree) {
  1279. return Math.max.apply(Math, tree.datas.map(function(o) {return o.level}));
  1280. },
  1281. calculateNode: function (tree, node) {
  1282. if (node.children && node.children.length > 0) {
  1283. const gather = node.children.reduce(function (rst, x) {
  1284. const result = {};
  1285. for (const cf of tree.setting.calcFields) {
  1286. result[cf] = ZhCalc.add(rst[cf], x[cf]);
  1287. }
  1288. return result;
  1289. });
  1290. // 汇总子项
  1291. for (const cf of tree.setting.calcFields) {
  1292. if (gather[cf]) {
  1293. node[cf] = gather[cf];
  1294. } else {
  1295. node[cf] = null;
  1296. }
  1297. }
  1298. }
  1299. // 自身运算
  1300. if (tree.setting.calcFun) {
  1301. tree.setting.calcFun(node);
  1302. }
  1303. },
  1304. calculateLevelNode: function (tree, level) {
  1305. const nodes = tree.datas.filter((n) => { return n.level === level });
  1306. for (const node of nodes) {
  1307. this.calculateNode(tree, node);
  1308. }
  1309. },
  1310. calculateAll: function (tree) {
  1311. const [maxLevel, levelMap] = this.mapTreeNode(tree);
  1312. for (let i = maxLevel; i >= 0; i--) {
  1313. const levelNodes = levelMap[i];
  1314. if (levelNodes && levelNodes.length > 0) {
  1315. for (const node of levelNodes) {
  1316. this.calculateNode(tree, node);
  1317. }
  1318. }
  1319. }
  1320. },
  1321. calculateParent: function (tree, node) {
  1322. const nodes = tree.getFullPathNodes(node.full_path);
  1323. nodes.sort((a, b) => {
  1324. return b.level - a.level;
  1325. });
  1326. for (const n of nodes) {
  1327. this.calculateNode(tree, n);
  1328. }
  1329. return nodes;
  1330. }
  1331. };