path_tree.js 41 KB

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