path_tree.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. const createNewPathTree = function (setting) {
  2. const treeSetting = JSON.parse(JSON.stringify(setting));
  3. const itemsPre = 'id_';
  4. const PathTree = function () {
  5. // 无索引
  6. this.datas = [];
  7. // 以key为索引
  8. this.items = {};
  9. // 以排序为索引
  10. this.nodes = [];
  11. };
  12. const proto = PathTree.prototype;
  13. /**
  14. * 树结构根据显示排序
  15. */
  16. proto.sortTreeNode = function () {
  17. const self = this;
  18. const addSortNodes = function (nodes) {
  19. for (let i = 0; i < nodes.length; i++) {
  20. self.nodes.push(nodes[i]);
  21. addSortNodes(self.getChildren(nodes[i]));
  22. }
  23. };
  24. self.nodes = [];
  25. addSortNodes(this.getChildren(null));
  26. };
  27. /**
  28. * 加载数据(初始化), 并给数据添加部分树结构必须数据
  29. * @param datas
  30. */
  31. proto.loadDatas = function (datas) {
  32. // 清空旧数据
  33. this.items = {};
  34. this.nodes = [];
  35. // 加载全部数据
  36. for (const data of datas) {
  37. const keyName = itemsPre + data[treeSetting.id];
  38. this.items[keyName] = JSON.parse(JSON.stringify(data));
  39. this.datas.push(this.items[keyName]);
  40. }
  41. this.sortTreeNode();
  42. for (const node of this.nodes) {
  43. const children = this.getChildren(node);
  44. node.expanded = children.length > 0;
  45. node.visible = true;
  46. }
  47. };
  48. /**
  49. * 加载数据(动态),只加载不同部分
  50. * @param {Array} datas
  51. * @return {Array} 加载到树的数据
  52. * @privateA
  53. */
  54. proto._updateData = function (datas) {
  55. const loadedData = [];
  56. for (const data of datas) {
  57. let node = this.getItems(data[treeSetting.id]);
  58. if (node) {
  59. for (const prop in node) {
  60. if (data[prop] !== undefined) {
  61. node[prop] = data[prop];
  62. }
  63. }
  64. loadedData.push(node);
  65. }
  66. }
  67. this.sortTreeNode();
  68. return loadedData;
  69. };
  70. /**
  71. * 加载数据(动态),只加载不同部分
  72. * @param {Array} datas
  73. * @return {Array} 加载到树的数据
  74. * @privateA
  75. */
  76. proto._loadData = function (datas) {
  77. const loadedData = [];
  78. for (const data of datas) {
  79. let node = this.getItems(data[treeSetting.id]);
  80. if (node) {
  81. for (const prop in node) {
  82. if (data[prop] !== undefined) {
  83. node[prop] = data[prop];
  84. }
  85. }
  86. loadedData.push(node);
  87. } else {
  88. const keyName = itemsPre + data[treeSetting.id];
  89. const node = JSON.parse(JSON.stringify(data));
  90. this.items[keyName] = node;
  91. this.datas.push(node);
  92. node.expanded = false;
  93. node.visible = true;
  94. loadedData.push(node);
  95. }
  96. }
  97. this.sortTreeNode();
  98. return loadedData;
  99. };
  100. /**
  101. * 清理数据(动态)
  102. * @param datas
  103. * @private
  104. */
  105. proto._freeData = function (datas) {
  106. const removeArrayData = function (array, data) {
  107. const index = array.indexOf(data);
  108. array.splice(index, 1);
  109. };
  110. for (const data of datas) {
  111. const node = this.getItems(data[treeSetting.id]);
  112. if (node) {
  113. delete this.items[itemsPre + node[treeSetting.id]];
  114. removeArrayData(this.datas, node);
  115. removeArrayData(this.nodes, node);
  116. }
  117. }
  118. };
  119. /**
  120. * 根据id获取树结构节点数据
  121. * @param {Number} id
  122. * @returns {Object}
  123. */
  124. proto.getItems = function (id) {
  125. return this.items[itemsPre + id];
  126. };
  127. /**
  128. * 查找node的parent
  129. * @param {Object} node
  130. * @returns {Object}
  131. */
  132. proto.getParent = function (node) {
  133. return this.getItems(node[treeSetting.pid]);
  134. };
  135. /**
  136. * 查询node的已下载子节点
  137. * @param {Object} node
  138. * @returns {Array}
  139. */
  140. proto.getChildren = function (node) {
  141. const pid = node ? node[treeSetting.id] : treeSetting.rootId;
  142. const children = this.datas.filter(function (x) {
  143. return x[treeSetting.pid] === pid;
  144. });
  145. children.sort(function (a, b) {
  146. return a.order - b.order;
  147. });
  148. return children;
  149. };
  150. /**
  151. * 查询node的已下载的全部后代
  152. * @param {Object} node
  153. * @returns {Array}
  154. */
  155. proto.getPosterity = function (node) {
  156. const reg = new RegExp('^' + node.full_path + '.');
  157. return this.datas.filter(function (x) {
  158. return reg.test(x.full_path);
  159. })
  160. };
  161. /**
  162. * 查询node是否是父节点的最后一个子节点
  163. * @param {Object} node
  164. * @returns {boolean}
  165. */
  166. proto.isLastSibling = function (node) {
  167. const siblings = this.getChildren(this.getParent(node));
  168. return node.order === siblings.length;
  169. };
  170. /**
  171. * 刷新子节点是否可见
  172. * @param {Object} node
  173. * @private
  174. */
  175. proto._refreshChildrenVisible = function (node) {
  176. const children = this.getChildren(node);
  177. for (const child of children) {
  178. child.visible = node.expanded && node.visible;
  179. this._refreshChildrenVisible(child);
  180. }
  181. }
  182. /**
  183. * 设置节点是否展开, 并控制子节点可见
  184. * @param {Object} node
  185. * @param {Boolean} expanded
  186. */
  187. proto.setExpanded = function (node, expanded) {
  188. node.expanded = expanded;
  189. this._refreshChildrenVisible(node);
  190. };
  191. /**
  192. * 提取节点key和索引数据
  193. * @param {Object} node - 节点
  194. * @returns {key}
  195. */
  196. proto.getNodeKeyData = function (node) {
  197. const data = {};
  198. for (const key of treeSetting.keys) {
  199. data[key] = node[key];
  200. }
  201. return data;
  202. }
  203. /**
  204. * 以下方法需等待响应, 通过callback刷新界面
  205. */
  206. /**
  207. * 加载子节点
  208. * @param {Object} node
  209. * @param {function} callback
  210. */
  211. proto.loadChildren = function (node, callback) {
  212. const self = this;
  213. const url = treeSetting.preUrl ? treeSetting.preUrl + '/get-children' : 'get-children';
  214. postData(url, this.getNodeKeyData(node), function (data) {
  215. self._loadData(data);
  216. callback();
  217. });
  218. };
  219. /**
  220. * 树结构基本操作
  221. * @param {String} url - 请求地址
  222. * @param {Object} node - 操作节点
  223. * @param {String} type - 操作类型
  224. * @param {function} callback - 界面刷新
  225. */
  226. proto.baseOperation = function (url, node, type, callback) {
  227. const self = this;
  228. const data = {
  229. id: node[treeSetting.id],
  230. postType: type
  231. };
  232. postData(url, data, function (datas) {
  233. const result = {};
  234. if (datas.update) {
  235. result.update = self._updateData(datas.update);
  236. }
  237. if (datas.create) {
  238. result.create = self._loadData(datas.create);
  239. }
  240. if (datas.delete) {
  241. result.delete = self._freeData(datas.delete);
  242. }
  243. callback(result);
  244. });
  245. };
  246. /**
  247. * 节点数据编辑
  248. * @param {String} url - 请求地址
  249. * @param {Array|Object} updateData - 需更新的数据
  250. * @param {function} callback - 界面刷新
  251. */
  252. proto.update = function (url, updateData, callback) {
  253. const self = this;
  254. postData(url, updateData, function (datas) {
  255. const result = self._updateData(datas);
  256. callback(result);
  257. }, function () {
  258. if (updateData instanceof Array) {
  259. const result = [];
  260. for (const data of updateData) {
  261. result.push(self.getItems(data[treeSetting.id]));
  262. }
  263. callback(result)
  264. } else {
  265. callback([self.getItems(updateData[treeSetting.id])]);
  266. }
  267. });
  268. };
  269. /**
  270. * 复制粘贴整块(目前仅可粘贴为后项)
  271. * @param {String} url - 请求地址
  272. * @param {Object} node - 操作节点
  273. * @param {Array} block - 被复制整块的节点列表
  274. * @param {function} callback - 界面刷新
  275. */
  276. proto.pasteBlock = function (url, node, block, callback) {
  277. const self = this;
  278. const data = {
  279. id: node[treeSetting.id],
  280. block: block
  281. };
  282. postData(url, data, function (datas) {
  283. const result = {};
  284. if (datas.update) {
  285. result.update = self._updateData(datas.update);
  286. }
  287. if (datas.create) {
  288. result.create = self._loadData(datas.create);
  289. }
  290. if (datas.delete) {
  291. result.delete = self._freeData(datas.delete);
  292. }
  293. callback(result);
  294. });
  295. };
  296. return new PathTree();
  297. }