/** * 重构前备份 * * 构建pathTree * 可动态加载子节点,要求子节点获取接口按/xxx/get-children定义 * @param {Object} setting - 设置 * @returns {PathTree} */ const createNewPathTree = function (setting) { const treeSetting = JSON.parse(JSON.stringify(setting)); const itemsPre = 'id_'; const PathTree = function () { // 无索引 this.datas = []; // 以key为索引 this.items = {}; // 以排序为索引 this.nodes = []; }; const proto = PathTree.prototype; /** * 树结构根据显示排序 */ proto.sortTreeNode = function () { const self = this; const addSortNodes = function (nodes) { for (let i = 0; i < nodes.length; i++) { self.nodes.push(nodes[i]); addSortNodes(self.getChildren(nodes[i])); } }; self.nodes = []; addSortNodes(this.getChildren(null)); }; /** * 加载数据(初始化), 并给数据添加部分树结构必须数据 * @param datas */ proto.loadDatas = function (datas) { // 清空旧数据 this.items = {}; this.nodes = []; // 加载全部数据 for (const data of datas) { const keyName = itemsPre + data[treeSetting.id]; this.items[keyName] = JSON.parse(JSON.stringify(data)); this.datas.push(this.items[keyName]); } this.sortTreeNode(); for (const node of this.nodes) { const children = this.getChildren(node); node.expanded = children.length > 0; node.visible = true; } }; /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ proto._updateData = function (datas) { const loadedData = []; for (const data of datas) { let node = this.getItems(data[treeSetting.id]); if (node) { for (const prop in node) { if (data[prop] !== undefined) { node[prop] = data[prop]; } } loadedData.push(node); } } for (const node of loadedData) { const children = this.getChildren(node); node.expanded = children.length > 0 && children[0].visible; } this.sortTreeNode(); return loadedData; }; /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ proto._loadData = function (datas) { const loadedData = []; for (const data of datas) { let node = this.getItems(data[treeSetting.id]); if (node) { for (const prop in node) { if (data[prop] !== undefined) { node[prop] = data[prop]; } } loadedData.push(node); } else { const keyName = itemsPre + data[treeSetting.id]; const node = JSON.parse(JSON.stringify(data)); this.items[keyName] = node; this.datas.push(node); node.expanded = false; node.visible = true; loadedData.push(node); } } this.sortTreeNode(); for (const node of loadedData) { const children = this.getChildren(node); if (!node.expanded && children.length > 0) { node.expanded = true; this._refreshChildrenVisible(node); } } return loadedData; }; /** * 清理数据(动态) * @param datas * @private */ proto._freeData = function (datas) { const removeArrayData = function (array, data) { const index = array.indexOf(data); array.splice(index, 1); }; for (const data of datas) { const node = this.getItems(data[treeSetting.id]); if (node) { delete this.items[itemsPre + node[treeSetting.id]]; removeArrayData(this.datas, node); removeArrayData(this.nodes, node); } } }; /** * 加载需展开的数据 * @param {Array} datas * @returns {Array} * @private */ proto._loadExpandData = function (datas) { const loadedData = [], existData = [], expandData = []; for (const data of datas) { let node = this.getItems(data[treeSetting.id]); if (node) { existData.push(node); } else { const keyName = itemsPre + data[treeSetting.id]; const node = JSON.parse(JSON.stringify(data)); this.items[keyName] = node; this.datas.push(node); node.expanded = false; node.visible = true; loadedData.push(node); } } this.sortTreeNode(); for (const node of loadedData) { const children = this.getChildren(node); if (!node.expanded && children.length > 0) { node.expaned = true; this._refreshChildrenVisible(node); } } for (const node of existData) { const children = this.getChildren(node); if (!node.expanded && children.length > 0) { node.expanded = children.length > 0; this._refreshChildrenVisible(node); expandData.push(node); } } return [loadedData, expandData]; }; /** * 根据id获取树结构节点数据 * @param {Number} id * @returns {Object} */ proto.getItems = function (id) { return this.items[itemsPre + id]; }; /** * 查找node的parent * @param {Object} node * @returns {Object} */ proto.getParent = function (node) { return this.getItems(node[treeSetting.pid]); }; /** * 查询node的已下载子节点 * @param {Object} node * @returns {Array} */ proto.getChildren = function (node) { const pid = node ? node[treeSetting.id] : treeSetting.rootId; const children = this.datas.filter(function (x) { return x[treeSetting.pid] === pid; }); children.sort(function (a, b) { return a.order - b.order; }); return children; }; /** * 查询node的已下载的全部后代 * @param {Object} node * @returns {Array} */ proto.getPosterity = function (node) { const reg = new RegExp('^' + node.full_path + '.'); return this.datas.filter(function (x) { return reg.test(x.full_path); }) }; /** * 查询node是否是父节点的最后一个子节点 * @param {Object} node * @returns {boolean} */ proto.isLastSibling = function (node) { const siblings = this.getChildren(this.getParent(node)); return node[this.setting.order] === siblings[siblings.length - 1][this.setting.order]; }; /** * 刷新子节点是否可见 * @param {Object} node * @private */ proto._refreshChildrenVisible = function (node) { const children = this.getChildren(node); for (const child of children) { child.visible = node.expanded && node.visible; this._refreshChildrenVisible(child); } } /** * 设置节点是否展开, 并控制子节点可见 * @param {Object} node * @param {Boolean} expanded */ proto.setExpanded = function (node, expanded) { node.expanded = expanded; this._refreshChildrenVisible(node); }; /** * 提取节点key和索引数据 * @param {Object} node - 节点 * @returns {key} */ proto.getNodeKeyData = function (node) { const data = {}; for (const key of treeSetting.keys) { data[key] = node[key]; } return data; } /** * 得到树结构构成id * @param node * @returns {*} */ proto.getNodeKey = function (node) { return node[treeSetting.id]; } /** * 以下方法需等待响应, 通过callback刷新界面 */ /** * 加载子节点 * @param {Object} node * @param {function} callback */ proto.loadChildren = function (node, callback) { const self = this; const url = treeSetting.preUrl ? treeSetting.preUrl + '/get-children' : 'get-children'; postData(url, this.getNodeKeyData(node), function (data) { self._loadData(data); callback(); }); }; /** * 树结构基本操作 * @param {String} url - 请求地址 * @param {Object} node - 操作节点 * @param {String} type - 操作类型 * @param {function} callback - 界面刷新 */ proto.baseOperation = function (url, node, type, callback) { const self = this; const data = { id: node[treeSetting.id], postType: type }; postData(url, data, function (datas) { const result = {}; if (datas.update) { result.update = self._updateData(datas.update); } if (datas.create) { result.create = self._loadData(datas.create); } if (datas.delete) { result.delete = self._freeData(datas.delete); } callback(result); }); }; /** * 节点数据编辑 * @param {String} url - 请求地址 * @param {Array|Object} updateData - 需更新的数据 * @param {function} callback - 界面刷新 */ proto.update = function (url, updateData, callback) { const self = this; postData(url, updateData, function (datas) { const result = self._updateData(datas); callback(result); }, function () { if (updateData instanceof Array) { const result = []; for (const data of updateData) { result.push(self.getItems(data[treeSetting.id])); } callback(result) } else { callback([self.getItems(updateData[treeSetting.id])]); } }); }; /** * 复制粘贴整块(目前仅可粘贴为后项) * @param {String} url - 请求地址 * @param {Object} node - 操作节点 * @param {Array} block - 被复制整块的节点列表 * @param {function} callback - 界面刷新 */ proto.pasteBlock = function (url, node, block, callback) { const self = this; const data = { id: node[treeSetting.id], block: block }; postData(url, data, function (datas) { const result = {}; if (datas.update) { result.update = self._updateData(datas.update); } if (datas.create) { result.create = self._loadData(datas.create); } if (datas.delete) { result.delete = self._freeData(datas.delete); } callback(result); }); }; /** * 提交数据 * @param {String} url - 请求地址 * @param {Object} node - 当前选中节点 * @param {Object} data - 提交的数据 * @param {function} callback - 界面刷新 */ proto.postData = function (url, node, data, callback) { const self = this; data.id = node[treeSetting.id]; postData(url, data, function (datas) { const result = {}; if (datas.update) { result.update = self._updateData(datas.update); } if (datas.create) { result.create = self._loadData(datas.create); } if (datas.delete) { result.delete = self._freeData(datas.delete); } if (datas.expand) { const [create, update] = self._loadExpandData(datas.expand); result.create = result.create.concat(create); result.expand = update; } callback(result); }); }; proto.batchInsert = function (url, node, data, callback) { const self = this; data.id = node[treeSetting.id]; postData(url, data, function (datas) { const result = {}; if (datas.update) { result.update = self._updateData(datas.update); } if (datas.create) { result.create = self._loadData(datas.create); } if (datas.delete) { result.delete = self._freeData(datas.delete); } callback(result); }); } return new PathTree(); }