path_tree.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. const createNewPathTree = function (setting) {
  2. const treeSetting = JSON.parse(JSON.stringify(setting));
  3. const itemsPre = 'id_';
  4. const postData = function (url, data, successCallback) {
  5. $.ajax({
  6. type:"POST",
  7. url: url,
  8. data: {'data': JSON.stringify(data)},
  9. dataType: 'json',
  10. cache: false,
  11. timeout: 5000,
  12. beforeSend: function(xhr) {
  13. let csrfToken = Cookies.get('csrfToken');
  14. xhr.setRequestHeader('x-csrf-token', csrfToken);
  15. },
  16. success: function(result){
  17. if (result.err === 0) {
  18. if (successCallback) {
  19. successCallback(result.data);
  20. }
  21. } else {
  22. toast('error: ' + result.message, 'error', 'exclamation-circle');
  23. }
  24. },
  25. error: function(jqXHR, textStatus, errorThrown){
  26. toast('error ' + textStatus + " " + errorThrown, 'error', 'exclamation-circle');
  27. }
  28. });
  29. };
  30. const PathTree = function () {
  31. // 无索引
  32. this.datas = [];
  33. // 以key为索引
  34. this.items = {};
  35. // 以排序为索引
  36. this.nodes = [];
  37. };
  38. const proto = PathTree.prototype;
  39. /**
  40. * 树结构根据显示排序
  41. */
  42. proto.sortTreeNode = function () {
  43. const self = this;
  44. const addSortNodes = function (nodes) {
  45. for (let i = 0; i < nodes.length; i++) {
  46. self.nodes.push(nodes[i]);
  47. addSortNodes(self.getChildren(nodes[i]));
  48. }
  49. };
  50. self.nodes = [];
  51. addSortNodes(this.getChildren(null));
  52. };
  53. /**
  54. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  55. * @param datas
  56. */
  57. proto.loadDatas = function (datas) {
  58. // 清空旧数据
  59. this.items = {};
  60. this.nodes = [];
  61. // 加载全部数据
  62. for (const data of datas) {
  63. const keyName = itemsPre + data[treeSetting.id];
  64. this.items[keyName] = JSON.parse(JSON.stringify(data));
  65. this.datas.push(this.items[keyName]);
  66. }
  67. this.sortTreeNode();
  68. for (const node of this.nodes) {
  69. const children = this.getChildren(node);
  70. node.expanded = children.length > 0;
  71. node.visible = true;
  72. }
  73. };
  74. /**
  75. * 加载数据(动态),只加载不同部分
  76. * @param {Array} datas
  77. * @privateA
  78. */
  79. proto._loadData = function (datas) {
  80. for (const data of datas) {
  81. let node = this.getItems(data[treeSetting]);
  82. if (node) {
  83. for (const prop of node.propertyNameList) {
  84. if (data[prop]) {
  85. node[prop] = data[prop];
  86. }
  87. }
  88. } else {
  89. const keyName = itemsPre + data[treeSetting.id];
  90. const node = JSON.parse(JSON.stringify(data));
  91. this.items[keyName] = node;
  92. this.datas.push(node);
  93. node.expanded = false;
  94. node.visible = true;
  95. }
  96. }
  97. this.sortTreeNode();
  98. }
  99. /**
  100. * 根据id获取树结构节点数据
  101. * @param {Number} id
  102. * @returns {Object}
  103. */
  104. proto.getItems = function (id) {
  105. return this.items[itemsPre + id];
  106. };
  107. /**
  108. * 查找node的parent
  109. * @param {Object} node
  110. * @returns {Object}
  111. */
  112. proto.getParent = function (node) {
  113. return this.getItems(node[treeSetting.pid]);
  114. };
  115. /**
  116. * 查询node的已下载子节点
  117. * @param {Object} node
  118. * @returns {Array}
  119. */
  120. proto.getChildren = function (node) {
  121. const pid = node ? node[treeSetting.id] : treeSetting.rootId;
  122. const children = this.datas.filter(function (x) {
  123. return x[treeSetting.pid] === pid;
  124. });
  125. children.sort(function (a, b) {
  126. return a.order - b.order;
  127. });
  128. return children;
  129. };
  130. /**
  131. * 查询node的已下载的全部后代
  132. * @param {Object} node
  133. * @returns {Array}
  134. */
  135. proto.getPosterity = function (node) {
  136. const reg = new RegExp('^' + node.full_path);
  137. return this.datas.filter(function (x) {
  138. return reg.test(x.full_path);
  139. })
  140. };
  141. /**
  142. * 查询node是否是父节点的最后一个子节点
  143. * @param {Object} node
  144. * @returns {boolean}
  145. */
  146. proto.isLastSibling = function (node) {
  147. const siblings = this.getChildren(this.getParent(node));
  148. return node.order === siblings.length;
  149. };
  150. /**
  151. * 刷新子节点是否可见
  152. * @param {Object} node
  153. * @private
  154. */
  155. proto._refreshChildrenVisible = function (node) {
  156. const children = this.getChildren(node);
  157. for (const child of children) {
  158. child.visible = node.expanded && node.visible;
  159. this._refreshChildrenVisible(child);
  160. }
  161. }
  162. /**
  163. * 设置节点是否展开, 并控制子节点可见
  164. * @param {Object} node
  165. * @param {Boolean} expanded
  166. */
  167. proto.setExpanded = function (node, expanded) {
  168. node.expanded = expanded;
  169. this._refreshChildrenVisible(node);
  170. };
  171. /**
  172. * 以下方法需等待响应
  173. */
  174. /**
  175. * 加载子节点, callback中应刷新界面
  176. * @param {Object} node
  177. * @param {function} callback
  178. */
  179. proto.loadChildren = function (node, callback) {
  180. const self = this;
  181. postData('get-children', {id: node[treeSetting.id]}, function (data) {
  182. self._loadData(data);
  183. callback();
  184. });
  185. }
  186. return new PathTree();
  187. }