path_tree.js 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383
  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. return this.datas.filter(function (x) {
  424. return reg.test(x.full_path);
  425. });
  426. } else {
  427. return this._recursiveGetPosterity(node);
  428. }
  429. };
  430. /**
  431. * 查询node是否是父节点的最后一个子节点
  432. * @param {Object} node
  433. * @returns {boolean}
  434. */
  435. isLastSibling (node) {
  436. const siblings = this.getChildren(this.getParent(node));
  437. return node.order === siblings[siblings.length - 1].order;
  438. };
  439. /**
  440. * 刷新子节点是否可见
  441. * @param {Object} node
  442. * @private
  443. */
  444. _refreshChildrenVisible (node) {
  445. if (!node.children) {
  446. node.children = this.getChildren(node);
  447. }
  448. if (node.children && node.children.length > 0) {
  449. for (const child of node.children) {
  450. child.visible = node.expanded && node.visible;
  451. this._refreshChildrenVisible(child);
  452. }
  453. }
  454. };
  455. /**
  456. * 设置节点是否展开, 并控制子节点可见
  457. * @param {Object} node
  458. * @param {Boolean} expanded
  459. */
  460. setExpanded (node, expanded) {
  461. node.expanded = expanded;
  462. this._refreshChildrenVisible(node);
  463. };
  464. /**
  465. * 提取节点key和索引数据
  466. * @param {Object} node - 节点
  467. * @returns {key}
  468. */
  469. getNodeKeyData (node) {
  470. const data = {};
  471. for (const key of this.setting.keys) {
  472. data[key] = node[key];
  473. }
  474. return data;
  475. };
  476. /**
  477. * 得到树结构构成id
  478. * @param node
  479. * @returns {*}
  480. */
  481. getNodeKey (node) {
  482. return node[this.setting.id];
  483. };
  484. /**
  485. * 递归 设置节点展开状态
  486. * @param {Array} nodes - 需要设置状态的节点
  487. * @param {Object} parent - nodes的父节点
  488. * @param {Function} checkFun - 判断节点展开状态的方法
  489. * @private
  490. */
  491. _recursiveExpand(nodes, parent, checkFun) {
  492. for (const node of nodes) {
  493. node.expanded = checkFun(node);
  494. node.visible = parent ? (parent.expanded && parent.visible) : true;
  495. this._recursiveExpand(node.children, node, checkFun);
  496. }
  497. }
  498. /**
  499. * 自定义展开规则
  500. * @param checkFun
  501. */
  502. expandByCustom(checkFun) {
  503. this._recursiveExpand(this.children, null, checkFun);
  504. }
  505. /**
  506. * 展开到第几层
  507. * @param {Number} level - 展开层数
  508. */
  509. expandByLevel(level) {
  510. // function recursiveExpand(nodes, parent) {
  511. // for (const node of nodes) {
  512. // node.expanded = node.level < level;
  513. // node.visible = parent ? (parent.expanded && parent.visible) : true;
  514. // recursiveExpand(node.children, node);
  515. // }
  516. // }
  517. // recursiveExpand(this.children);
  518. this.expandByCustom(function (n) {
  519. return n.level < level;
  520. });
  521. }
  522. /**
  523. * 自动展开节点node
  524. * @param node
  525. * @returns {*}
  526. */
  527. autoExpandNode(node) {
  528. const parents = this.getAllParents(node);
  529. const reload = [];
  530. for (const p of parents) {
  531. if (!p.expanded) {
  532. reload.push(p);
  533. this.setExpanded(p, true);
  534. }
  535. }
  536. return reload;
  537. }
  538. }
  539. class MeasureTree extends BaseTree {
  540. addData (datas) {
  541. const loadedData = [];
  542. for (const data of datas) {
  543. let node = this.getItems(data[this.setting.id]);
  544. if (node) {
  545. for (const prop in node) {
  546. if (data[prop] !== undefined) {
  547. node[prop] = data[prop];
  548. }
  549. }
  550. loadedData.push(node);
  551. } else {
  552. const keyName = itemsPre + data[this.setting.id];
  553. const node = JSON.parse(JSON.stringify(data));
  554. this.items[keyName] = node;
  555. this.datas.push(node);
  556. node.expanded = false;
  557. node.visible = true;
  558. loadedData.push(node);
  559. }
  560. }
  561. this.sortTreeNode();
  562. for (const node of loadedData) {
  563. const children = node.children;
  564. if (!node.expanded && children.length > 0) {
  565. node.expanded = true;
  566. this._refreshChildrenVisible(node);
  567. }
  568. }
  569. return loadedData;
  570. }
  571. removeData (datas) {
  572. datas.sort(function (a, b) {
  573. return b.level - a.level;
  574. });
  575. const removeArrayData = function (array, data) {
  576. const index = array.indexOf(data);
  577. array.splice(index, 1);
  578. };
  579. for (const data of datas) {
  580. const node = this.getItems(data[this.setting.id]);
  581. if (node && this.getChildren(node).length === 0) {
  582. delete this.items[itemsPre + node[this.setting.id]];
  583. if (node[this.setting.pid] !== this.setting.rootId) {
  584. const parent = this.items[itemsPre + node[this.setting.pid]];
  585. removeArrayData(parent.children, node);
  586. }
  587. removeArrayData(this.datas, node);
  588. removeArrayData(this.nodes, node);
  589. }
  590. }
  591. };
  592. loadLeafData (data) {
  593. const datas = data instanceof Array ? data : [data];
  594. for (const d of datas) {
  595. let node = this.getItems(d[this.setting.id]);
  596. if (node && node.is_leaf) {
  597. for (const prop in node) {
  598. if (data[prop] !== undefined) {
  599. node[prop] = d[prop];
  600. }
  601. }
  602. }
  603. }
  604. };
  605. }
  606. class FxTree extends BaseTree {
  607. /**
  608. * 检查节点是否是最底层项目节
  609. * @param node
  610. * @returns {boolean}
  611. */
  612. isLeafXmj(node) {
  613. if (!node.code) {
  614. return false;
  615. }
  616. for (const child of node.children) {
  617. if (!child.b_code || child.b_code === '') {
  618. return false;
  619. }
  620. }
  621. return true;
  622. }
  623. /**
  624. * 查询最底层项目节(本身或父项)
  625. * @param {Object} node - 查询节点
  626. * @returns {Object}
  627. */
  628. getLeafXmjParent(node) {
  629. let parent = node;
  630. while (parent) {
  631. if (this.isLeafXmj(parent)) {
  632. return parent;
  633. } else {
  634. parent = this.getParent(parent);
  635. }
  636. }
  637. return null;
  638. }
  639. /**
  640. * 展开至最底层项目节
  641. */
  642. expandToLeafXmj() {
  643. const self = this;
  644. this.expandByCustom(function (node) {
  645. if (node.b_code && node.b_code !== '') {
  646. return false;
  647. } else {
  648. return !self.isLeafXmj(node);
  649. }
  650. })
  651. }
  652. /**
  653. * 展开至计算项
  654. */
  655. expandByCalcFields() {
  656. const self = this;
  657. this.expandByCustom(function (node) {
  658. for (const field of self.setting.calcFields) {
  659. if (node[field]) {
  660. return true;
  661. }
  662. }
  663. return false;
  664. })
  665. }
  666. }
  667. class LedgerTree extends FxTree {
  668. /**
  669. * 加载数据(动态),只加载不同部分
  670. * @param {Array} datas
  671. * @return {Array} 加载到树的数据
  672. * @privateA
  673. */
  674. _updateData (datas) {
  675. datas = datas instanceof Array ? datas : [datas];
  676. let loadedData = [];
  677. for (const data of datas) {
  678. let node = this.getItems(data[this.setting.id]);
  679. if (node) {
  680. for (const prop in node) {
  681. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  682. if (prop === this.setting.pid) {
  683. loadedData.push(this.getItems(node[this.setting.pid]));
  684. loadedData.push(this.getItems(data[this.setting.pid]));
  685. }
  686. if (prop === this.setting.order) {
  687. loadedData = loadedData.concat(this.getPosterity(node));
  688. }
  689. node[prop] = data[prop];
  690. }
  691. }
  692. loadedData.push(node);
  693. }
  694. }
  695. loadedData = _.uniq(loadedData);
  696. for (const node of loadedData) {
  697. node.children = this.getChildren(node);
  698. node.expanded = node.children.length === 0 ? true : node.children[0].visible;
  699. }
  700. this.sortTreeNode(true);
  701. return loadedData;
  702. };
  703. /**
  704. * 加载数据(动态),只加载不同部分
  705. * @param {Array} datas
  706. * @return {Array} 加载到树的数据
  707. * @privateA
  708. */
  709. _loadData (datas) {
  710. datas = datas instanceof Array ? datas : [datas];
  711. const loadedData = [], resortData = [];
  712. for (const data of datas) {
  713. let node = this.getItems(data[this.setting.id]);
  714. if (node) {
  715. const parent = this.getItems(node[this.setting.pid]);
  716. for (const prop in node) {
  717. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  718. node[prop] = data[prop];
  719. if (parent && resortData.indexOf(parent) === -1) {
  720. resortData.push(parent);
  721. }
  722. }
  723. }
  724. loadedData.push(node);
  725. } else {
  726. const keyName = itemsPre + data[this.setting.id];
  727. const node = JSON.parse(JSON.stringify(data));
  728. this.items[keyName] = node;
  729. this.datas.push(node);
  730. node.expanded = true;
  731. node.visible = true;
  732. loadedData.push(node);
  733. if (resortData.indexOf(node) === -1) {
  734. resortData.push(node);
  735. }
  736. const parent = this.getItems(node[this.setting.pid]);
  737. if (parent && resortData.indexOf(parent) === -1) {
  738. resortData.push(parent);
  739. }
  740. }
  741. }
  742. for (const node of resortData) {
  743. node.children = this.getChildren(node);
  744. }
  745. this.sortTreeNode(true);
  746. for (const node of loadedData) {
  747. if (!node.expanded) {
  748. this.setExpanded(node, true);
  749. }
  750. }
  751. return loadedData;
  752. };
  753. /**
  754. * 清理数据(动态)
  755. * @param datas
  756. * @private
  757. */
  758. _freeData (datas) {
  759. datas = datas instanceof Array ? datas : [datas];
  760. const freeDatas = [];
  761. const removeArrayData = function (array, data) {
  762. const index = array.indexOf(data);
  763. array.splice(index, 1);
  764. };
  765. for (const data of datas) {
  766. const node = this.getItems(data[this.setting.id]);
  767. if (node) {
  768. freeDatas.push(node);
  769. delete this.items[itemsPre + node[this.setting.id]];
  770. if (node[this.setting.pid] !== this.setting.rootId) {
  771. const parent = this.getItems(node[this.setting.pid]);
  772. if (parent) {
  773. removeArrayData(parent.children, node);
  774. }
  775. }
  776. removeArrayData(this.datas, node);
  777. removeArrayData(this.nodes, node);
  778. }
  779. }
  780. return freeDatas;
  781. };
  782. /**
  783. * 加载需展开的数据
  784. * @param {Array} datas
  785. * @returns {Array}
  786. * @private
  787. */
  788. _loadExpandData (datas) {
  789. datas = datas instanceof Array ? datas : [datas];
  790. const loadedData = [], existData = [], expandData = [], resortData = [];
  791. for (const data of datas) {
  792. let node = this.getItems(data[this.setting.id]);
  793. if (node) {
  794. existData.push(node);
  795. } else {
  796. const keyName = itemsPre + data[this.setting.id];
  797. const node = JSON.parse(JSON.stringify(data));
  798. this.items[keyName] = node;
  799. this.datas.push(node);
  800. node.expanded = false;
  801. node.visible = true;
  802. loadedData.push(node);
  803. if (resortData.indexOf(node) === -1) {
  804. resortData.push(node);
  805. }
  806. const parent = this.getItems(node[this.setting.pid]);
  807. if (parent && resortData.indexOf(parent) === -1) {
  808. resortData.push(parent);
  809. }
  810. }
  811. }
  812. for (const node of resortData) {
  813. node.children = this.getChildren(node);
  814. }
  815. this.sortTreeNode(true);
  816. for (const node of loadedData) {
  817. if (!node.expanded) {
  818. this.setExpanded(node, true);
  819. }
  820. }
  821. for (const node of existData) {
  822. const parent = this.getItems(node[this.setting.pid]);
  823. if (expandData.indexOf(parent) === -1) {
  824. expandData.push(parent);
  825. if (!parent.expanded) {
  826. this.setExpanded(parent, true);
  827. }
  828. }
  829. if (!node.expanded) {
  830. this.setExpanded(node, true);
  831. }
  832. }
  833. return [loadedData, expandData];
  834. };
  835. /**
  836. *
  837. * @param parent
  838. * @param node
  839. * @private
  840. */
  841. _getNodesParents(parents, nodes) {
  842. for (const node of nodes) {
  843. const parent = this.getParent(node);
  844. if (parent) {
  845. const paths = this.getFullPathNodes(parent.full_path);
  846. for (const p of paths) {
  847. if (parents.indexOf(p) === -1) {
  848. parents.push(p);
  849. }
  850. }
  851. }
  852. if (this.getItems(node.ledger_id) && node.children.length > 0) {
  853. parents.push(node);
  854. }
  855. }
  856. }
  857. _getReCalcNodes(reCalcNodes, nodes) {
  858. for (const node of nodes) {
  859. const parent = this.getParent(node);
  860. if (parent) {
  861. const paths = this.getFullPathNodes(parent.full_path);
  862. for (const p of paths) {
  863. if (reCalcNodes.indexOf(p) === -1) {
  864. reCalcNodes.push(p);
  865. }
  866. }
  867. }
  868. // 最底层项目节,也需要计算
  869. //if (this.getItems(node.ledger_id) && node.children.length > 0) {
  870. reCalcNodes.push(node);
  871. //}
  872. }
  873. }
  874. /**
  875. * 因为提交其他数据,引起的树结构数据更新,调用该方法
  876. *
  877. * @param data - 更新的数据 {update, create, delete}
  878. * @returns {{}}
  879. */
  880. loadPostData(data) {
  881. const result = {}, reCalcNodes = [];
  882. if (data.update) {
  883. result.update = this._updateData(data.update);
  884. this._getReCalcNodes(reCalcNodes, result.update);
  885. }
  886. if (data.create) {
  887. result.create = this._loadData(data.create);
  888. this._getReCalcNodes(reCalcNodes, result.create);
  889. }
  890. if (data.delete) {
  891. result.delete = this._freeData(data.delete);
  892. this._getReCalcNodes(reCalcNodes, result.delete);
  893. }
  894. reCalcNodes.sort((a, b) => {
  895. return b.level - a.level;
  896. });
  897. for (const node of reCalcNodes) {
  898. treeCalc.calculateNode(this, node, this.setting.calcFields, this.setting.calcFun);
  899. }
  900. result.update = result.update ? result.update.concat(reCalcNodes) : reCalcNodes;
  901. return result;
  902. }
  903. /**
  904. * 以下方法需等待响应, 通过callback刷新界面
  905. */
  906. /**
  907. * 加载子节点
  908. * @param {Object} node
  909. * @param {function} callback
  910. */
  911. loadChildren (node, callback) {
  912. const self = this;
  913. const url = this.setting.preUrl ? this.setting.preUrl + '/get-children' : 'get-children';
  914. postData(url, this.getNodeKeyData(node), function (data) {
  915. self._loadData(data);
  916. callback();
  917. });
  918. };
  919. /**
  920. * 树结构基本操作
  921. * @param {String} url - 请求地址
  922. * @param {Object} node - 操作节点
  923. * @param {String} type - 操作类型
  924. * @param {function} callback - 界面刷新
  925. */
  926. baseOperation (url, node, type, callback) {
  927. const self = this;
  928. const data = {
  929. id: node[this.setting.id],
  930. postType: type
  931. };
  932. postData(url, data, function (datas) {
  933. const refreshData = self.loadPostData(datas);
  934. callback(refreshData);
  935. });
  936. };
  937. /**
  938. * 节点数据编辑
  939. * @param {String} url - 请求地址
  940. * @param {Array|Object} updateData - 需更新的数据
  941. * @param {function} callback - 界面刷新
  942. */
  943. update (url, updateData, callback) {
  944. const self = this;
  945. postData(url, updateData, function (datas) {
  946. const refreshData = self.loadPostData(datas);
  947. callback(refreshData);
  948. }, function () {
  949. if (updateData instanceof Array) {
  950. const result = [];
  951. for (const data of updateData) {
  952. result.push(self.getItems(data[self.setting.id]));
  953. }
  954. callback(result)
  955. } else {
  956. callback([self.getItems(updateData[self.setting.id])]);
  957. }
  958. });
  959. };
  960. /**
  961. * 复制粘贴整块(目前仅可粘贴为后项)
  962. * @param {String} url - 请求地址
  963. * @param {Object} node - 操作节点
  964. * @param {Array} block - 被复制整块的节点列表
  965. * @param {function} callback - 界面刷新
  966. */
  967. pasteBlock (url, node, block, callback) {
  968. const self = this;
  969. const data = {
  970. id: node[self.setting.id],
  971. block: block
  972. };
  973. postData(url, data, function (datas) {
  974. const refreshData = self.loadPostData(datas);
  975. callback(refreshData);
  976. });
  977. };
  978. /**
  979. * 提交数据
  980. * @param {String} url - 请求地址
  981. * @param {Object} node - 当前选中节点
  982. * @param {Object} data - 提交的数据
  983. * @param {function} callback - 界面刷新
  984. */
  985. postData (url, node, data, callback) {
  986. const self = this;
  987. if (node) {
  988. data.id = node[self.setting.id];
  989. }
  990. postData(url, data, function (datas) {
  991. const refreshData = self.loadPostData(datas);
  992. callback(refreshData);
  993. // const result = {};
  994. // if (datas.update) {
  995. // result.update = self._updateData(datas.update);
  996. // }
  997. // if (datas.create) {
  998. // result.create = self._loadData(datas.create);
  999. // }
  1000. // if (datas.delete) {
  1001. // result.delete = self._freeData(datas.delete);
  1002. // }
  1003. // if (datas.expand) {
  1004. // const [create, update] = self._loadExpandData(datas.expand);
  1005. // result.create = result.create ? result.create.concat(create) : create;
  1006. // result.expand = update;
  1007. // }
  1008. // callback(result);
  1009. });
  1010. };
  1011. }
  1012. class StageTree extends FxTree {
  1013. /**
  1014. * 构造函数
  1015. */
  1016. constructor (setting) {
  1017. super(setting);
  1018. // stage关联索引
  1019. this.stageItems = {};
  1020. }
  1021. /**
  1022. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  1023. * @param datas
  1024. */
  1025. loadDatas (datas) {
  1026. super.loadDatas(datas);
  1027. // 清空旧数据
  1028. this.stageItems = {};
  1029. // 加载全部数据
  1030. for (const data of this.datas) {
  1031. const keyName = itemsPre + data[this.setting.stageId];
  1032. this.stageItems[keyName] = data;
  1033. }
  1034. }
  1035. getStageItems(id) {
  1036. return this.stageItems[itemsPre + id];
  1037. }
  1038. loadStageData(datas, fieldPre, fields) {
  1039. datas = datas instanceof Array ? datas : [datas];
  1040. const loadedData = [];
  1041. for (const data of datas) {
  1042. let node = this.getStageItems(data.lid);
  1043. if (node) {
  1044. for (const prop of fields) {
  1045. if (data[prop] !== undefined) {
  1046. node[fieldPre + prop] = data[prop];
  1047. }
  1048. }
  1049. loadedData.push(node);
  1050. }
  1051. }
  1052. }
  1053. loadPreStageData(datas) {
  1054. this.loadStageData(datas, 'pre_', this.setting.updateFields);
  1055. }
  1056. loadCurStageData(datas) {
  1057. this.loadStageData(datas, '', this.setting.updateFields);
  1058. }
  1059. /**
  1060. * 加载数据(动态),只加载不同部分
  1061. * @param {Array} datas
  1062. * @return {Array} 加载到树的数据
  1063. * @privateA
  1064. */
  1065. _updateData (datas) {
  1066. datas = datas instanceof Array ? datas : [datas];
  1067. let loadedData = [];
  1068. for (const data of datas) {
  1069. let node = this.getItems(data[this.setting.id]);
  1070. if (node) {
  1071. for (const prop in node) {
  1072. if (prop === this.setting.pid && data[prop] !== node[prop]) {
  1073. }
  1074. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  1075. if (prop === this.setting.pid) {
  1076. loadedData.push(this.getItems(node[this.setting.pid]));
  1077. loadedData.push(this.getItems(data[this.setting.pid]));
  1078. }
  1079. node[prop] = data[prop];
  1080. }
  1081. }
  1082. loadedData.push(node);
  1083. }
  1084. }
  1085. loadedData = _.uniq(loadedData);
  1086. for (const node of loadedData) {
  1087. node.children = this.getChildren(node);
  1088. node.expanded = node.children.length === 0 ? true : node.children[0].visible;
  1089. }
  1090. this.sortTreeNode(true);
  1091. return loadedData;
  1092. };
  1093. /**
  1094. * 加载数据(动态),只加载不同部分
  1095. * @param {Array} datas
  1096. * @return {Array} 加载到树的数据
  1097. * @privateA
  1098. */
  1099. _updateStageData (datas) {
  1100. datas = datas instanceof Array ? datas : [datas];
  1101. const loadedData = [];
  1102. for (const data of datas) {
  1103. let node = this.getStageItems(data.lid);
  1104. if (node) {
  1105. for (const prop of this.setting.updateFields) {
  1106. if (data[prop] !== undefined) {
  1107. node[prop] = data[prop];
  1108. }
  1109. }
  1110. loadedData.push(node);
  1111. }
  1112. }
  1113. return loadedData;
  1114. };
  1115. /**
  1116. *
  1117. * @param parent
  1118. * @param node
  1119. * @private
  1120. */
  1121. _getNodesParents(parents, nodes) {
  1122. for (const node of nodes) {
  1123. const parent = this.getParent(node);
  1124. if (parent) {
  1125. const paths = this.getFullPathNodes(parent.full_path);
  1126. for (const p of paths) {
  1127. if (parents.indexOf(p) === -1) {
  1128. parents.push(p);
  1129. }
  1130. }
  1131. }
  1132. if (node.children && node.children.length > 0) {
  1133. parents.push(node);
  1134. }
  1135. }
  1136. }
  1137. _updateDgnData(datas) {
  1138. datas = datas instanceof Array ? datas : [datas];
  1139. let loadedData = [];
  1140. for (const data of datas) {
  1141. let node = this.getStageItems(data.id);
  1142. if (node) {
  1143. for (const prop in data) {
  1144. if (data[prop] !== undefined && data[prop] !== node[prop]) {
  1145. node[prop] = data[prop];
  1146. }
  1147. }
  1148. loadedData.push(node);
  1149. }
  1150. }
  1151. return loadedData;
  1152. }
  1153. /**
  1154. * 提交数据至后端,返回的前端树结构应刷新的部分
  1155. * StageTree仅有更新CurStage部分,不需要增删
  1156. *
  1157. * @param data - 需要更新的数据
  1158. * @returns {Array} - 界面需要刷新的数据
  1159. */
  1160. loadPostStageData(data) {
  1161. let result, parents = [];
  1162. if (data.bills) {
  1163. result = this._updateData(data.bills);
  1164. this._getNodesParents(parents, result);
  1165. }
  1166. if (data.curStageData) {
  1167. result = this._updateStageData(data.curStageData);
  1168. this._getNodesParents(parents, result);
  1169. }
  1170. if (data.dgn) {
  1171. const dgnResult = this._updateDgnData(data.dgn);
  1172. result = result ? result.concat(dgnResult) : dgnResult;
  1173. }
  1174. result = result ? result.concat(parents) : parents;
  1175. result.sort((a, b) => {
  1176. return b.level - a.level;
  1177. });
  1178. for (const node of result) {
  1179. treeCalc.calculateNode(this, node);
  1180. }
  1181. return result;
  1182. }
  1183. }
  1184. class MasterTree extends FxTree {
  1185. /**
  1186. * 构造函数
  1187. */
  1188. constructor (setting) {
  1189. super(setting);
  1190. // 关联索引
  1191. this.masterItems = {};
  1192. }
  1193. /**
  1194. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  1195. * @param datas
  1196. */
  1197. loadDatas (datas) {
  1198. super.loadDatas(datas);
  1199. // 清空旧数据
  1200. this.masterItems = {};
  1201. // minor数据缓存
  1202. this.minorData = {};
  1203. // 加载全部数据
  1204. for (const data of this.datas) {
  1205. const keyName = itemsPre + data[this.setting.masterId];
  1206. this.masterItems[keyName] = data;
  1207. }
  1208. }
  1209. /**
  1210. * 根据关联id,查找节点
  1211. * @param id
  1212. * @returns {*}
  1213. */
  1214. getMasterItems(id) {
  1215. return this.masterItems[itemsPre + id];
  1216. }
  1217. /**
  1218. * 加载关联数据
  1219. *
  1220. * @param {Array|Object}datas - 需要关联的数据
  1221. * @param {String} fieldPre - 关联字段前缀(关联结果)
  1222. * @param {Array} fields - 关联字段
  1223. * @returns {Array}
  1224. */
  1225. loadMinorData(datas, fieldSuf, fields, calcFields) {
  1226. for (const cf of calcFields) {
  1227. this.setting.calcFields.push(cf+fieldSuf);
  1228. }
  1229. if (!datas) return;
  1230. datas = datas instanceof Array ? datas : [datas];
  1231. this.minorData[fieldSuf] = datas;
  1232. const loadedData = [];
  1233. for (const data of datas) {
  1234. let node = this.getMasterItems(data[this.setting.minorId]);
  1235. if (node) {
  1236. for (const prop of fields) {
  1237. if (data[prop] !== undefined) {
  1238. node[prop + fieldSuf] = data[prop];
  1239. }
  1240. }
  1241. loadedData.push(node);
  1242. }
  1243. }
  1244. return loadedData;
  1245. }
  1246. }
  1247. if (type === 'base') {
  1248. return new BaseTree(setting);
  1249. } else if (type === 'fx') {
  1250. return new FxTree(setting);
  1251. } else if (type === 'stage') {
  1252. return new StageTree(setting);
  1253. } else if (type === 'ledger') {
  1254. return new LedgerTree(setting);
  1255. } else if (type === 'measure') {
  1256. return new MeasureTree(setting);
  1257. } else if (type === 'master') {
  1258. return new MasterTree(setting);
  1259. }
  1260. };
  1261. const treeCalc = {
  1262. mapTreeNode: function (tree) {
  1263. let map = {}, maxLevel = 0;
  1264. for (const node of tree.nodes) {
  1265. let levelArr = map[node.level];
  1266. if (!levelArr) {
  1267. levelArr = [];
  1268. map[node.level] = levelArr;
  1269. }
  1270. if (node.level > maxLevel) {
  1271. maxLevel = node.level;
  1272. }
  1273. levelArr.push(node);
  1274. }
  1275. return [maxLevel, map];
  1276. },
  1277. getMaxLevel: function (tree) {
  1278. return Math.max.apply(Math, tree.datas.map(function(o) {return o.level}));
  1279. },
  1280. calculateNode: function (tree, node) {
  1281. if (node.children && node.children.length > 0) {
  1282. const gather = node.children.reduce(function (rst, x) {
  1283. const result = {};
  1284. for (const cf of tree.setting.calcFields) {
  1285. result[cf] = ZhCalc.add(rst[cf], x[cf]);
  1286. }
  1287. return result;
  1288. });
  1289. // 汇总子项
  1290. for (const cf of tree.setting.calcFields) {
  1291. if (gather[cf]) {
  1292. node[cf] = gather[cf];
  1293. } else {
  1294. node[cf] = null;
  1295. }
  1296. }
  1297. }
  1298. // 自身运算
  1299. if (tree.setting.calcFun) {
  1300. tree.setting.calcFun(node);
  1301. }
  1302. },
  1303. calculateLevelNode: function (tree, level) {
  1304. const nodes = tree.datas.filter((n) => { return n.level === level });
  1305. for (const node of nodes) {
  1306. this.calculateNode(tree, node);
  1307. }
  1308. },
  1309. calculateAll: function (tree) {
  1310. const [maxLevel, levelMap] = this.mapTreeNode(tree);
  1311. for (let i = maxLevel; i >= 0; i--) {
  1312. const levelNodes = levelMap[i];
  1313. if (levelNodes && levelNodes.length > 0) {
  1314. for (const node of levelNodes) {
  1315. this.calculateNode(tree, node);
  1316. }
  1317. }
  1318. }
  1319. },
  1320. calculateParent: function (tree, node) {
  1321. const nodes = tree.getFullPathNodes(node.full_path);
  1322. nodes.sort((a, b) => {
  1323. return b.level - a.level;
  1324. });
  1325. for (const n of nodes) {
  1326. this.calculateNode(tree, n);
  1327. }
  1328. return nodes;
  1329. }
  1330. };