'use strict'; /** * * * @author Mai * @date * @version */ const itemsPre = 'id_'; class baseTree { /** * 构造函数 */ constructor (ctx, setting) { this.ctx = ctx; // 无索引 this.datas = []; // 以key为索引 this.items = {}; // 以排序为索引 this.nodes = []; // 根节点 this.children = []; // 树设置 this.setting = setting; } /** * 根据id获取树结构节点数据 * @param {Number} id * @returns {Object} */ getItems (id) { return this.items[itemsPre + id]; }; /** * 查找node的parent * @param {Object} node * @returns {Object} */ getParent (node) { return this.getItems(node[this.setting.pid]); }; /** * 查询node的已下载子节点 * @param {Object} node * @returns {Array} */ getChildren (node) { const setting = this.setting; const pid = node ? node[setting.id] : setting.rootId; const children = this.datas.filter(function (x) { return x[setting.pid] === pid; }); children.sort(function (a, b) { return a.order - b.order; }); return children; }; /** * 获取节点的 index * @param node * @returns {number} */ getNodeSerialNo(node) { return this.nodes.indexOf(node); } /** * 树结构根据显示排序 */ sortTreeNode (isResort) { const self = this; const addSortNodes = function (nodes) { if (!nodes) { return } for (let i = 0; i < nodes.length; i++) { self.nodes.push(nodes[i]); nodes[i].index = self.nodes.length - 1; if (!isResort) { nodes[i].children = self.getChildren(nodes[i]); } else { nodes[i].children.sort(function (a, b) { return a.order - b.order; }) } addSortNodes(nodes[i].children); } }; this.nodes = []; if (!isResort) { this.children = this.getChildren(); } else { this.children.sort(function (a, b) { return a.order - b.order; }) } addSortNodes(this.children); } /** * 加载数据(初始化), 并给数据添加部分树结构必须数据 * @param datas */ loadDatas (datas) { // 清空旧数据 this.items = {}; this.nodes = []; this.datas = []; this.children = []; // 加载全部数据 datas.sort(function (a, b) { return a.level - b.level; }); for (const data of datas) { const keyName = itemsPre + data[this.setting.id]; if (!this.items[keyName]) { const item = JSON.parse(JSON.stringify(data)); item.children = []; item.expanded = true; item.visible = true; this.items[keyName] = item; this.datas.push(item); if (item[this.setting.pid] === this.setting.rootId) { this.children.push(item); } else { const parent = this.getParent(item); if (parent) { parent.children.push(item); } } } } this.children.sort(function (a, b) { return a.order - b.order; }); this.sortTreeNode(true); } /** * 递归方式 查询node的已下载的全部后代 (兼容full_path不存在的情况) * @param node * @returns {*} * @private */ _recursiveGetPosterity (node) { let posterity = node.children; for (const c of node.children) { posterity = posterity.concat(this._recursiveGetPosterity(c)); } return posterity; }; /** * 查询node的已下载的全部后代 * @param {Object} node * @returns {Array} */ getPosterity (node) { if (node.full_path !== '') { const reg = new RegExp('^' + node.full_path + '-'); return this.datas.filter(function (x) { return reg.test(x.full_path); }); } else { return this._recursiveGetPosterity(node); } }; /** * 根据 字段名称 获取数据 * @param fields * @returns {Array} */ getDatas (fields) { const datas = []; for (const node of this.nodes) { if (node.b_code && node.b_code !== '') node.chapter = this.ctx.helper.getChapterCode(node.b_code); const data = {}; for (const field of fields) { data[field] = node[field]; } datas.push(data); } return datas; } /** * 排除 某些字段 获取数据 * @param fields * @returns {Array} */ getDatasWithout (fields) { const datas = []; for (const node of this.nodes) { if (node.b_code && node.b_code !== '') node.chapter = this.ctx.helper.getChapterCode(node.b_code); const data = {}; for (const field in node) { if (fields.indexOf(field) === -1) { data[field] = node[field]; } } datas.push(data); } return datas; } /** * 获取默认数据 剔除一些树结构需要的缓存数据 * @returns {Array} */ getDefaultDatas() { return this.getDatasWithout(['expanded', 'visible', 'children', 'index']); } _mapTreeNode () { let map = {}, maxLevel = 0; for (const node of this.nodes) { let levelArr = map[node.level]; if (!levelArr) { levelArr = []; map[node.level] = levelArr; } if (node.level > maxLevel) { maxLevel = node.level; } levelArr.push(node); } return [maxLevel, map]; } _calculateNode (node, fun) { const self = this; if (node.children && node.children.length > 0) { const gather = node.children.reduce(function (rst, x) { const result = {}; for (const cf of self.setting.calcFields) { result[cf] = self.ctx.helper.add(rst[cf], x[cf]); } return result; }); // 汇总子项 for (const cf of this.setting.calcFields) { if (gather[cf]) { node[cf] = gather[cf]; } else { node[cf] = null; } } } // 自身运算 if (fun) { fun(node); } else if (this.setting.calc) { this.setting.calc(node); } } calculateAll(fun) { const [maxLevel, levelMap] = this._mapTreeNode(); for (let i = maxLevel; i >= 0; i--) { const levelNodes = levelMap[i]; if (levelNodes && levelNodes.length > 0) { for (const node of levelNodes) { this._calculateNode(node, fun); } } } } } class billsTree extends baseTree { /** * 检查节点是否是最底层项目节 * @param node * @returns {boolean} */ isLeafXmj(node) { if (node.b_code && node.b_code !== '') { return false; } for (const child of node.children) { if (!child.b_code || child.b_code === '') { return false; } } return true; } /** * 查询最底层项目节(本身或父项) * @param {Object} node - 查询节点 * @returns {Object} */ getLeafXmjParent(node) { let parent = node; while (parent) { if (this.isLeafXmj(parent)) { return parent; } else { parent = this.getParent(parent); } } return null; } } class filterTree extends baseTree { addData(data, fields) { const item = {}; for (const prop in data) { if (fields.indexOf(prop) >= 0) { item[prop] = data[prop]; } } const keyName = itemsPre + item[this.setting.id]; if (!this.items[keyName]) { item.children = []; item.is_leaf = true; item.expanded = true; item.visible = true; this.items[keyName] = item; this.datas.push(item); if (item[this.setting.pid] === this.setting.rootId) { this.children.push(item); } else { const parent = this.getParent(item); if (parent) { parent.is_leaf = false; parent.children.push(item); } } } else { return this.items[keyName]; } return item; } } class filterGatherTree extends baseTree { clearDatas() { this.items = {}; this.nodes = []; this.datas = []; this.children = []; } get newId() { if (!this._maxId) { this._maxId = 0; } this._maxId++; return this._maxId; } addNode(data, parent) { data[this.setting.pid] = parent ? parent[this.setting.id] : this.setting.rootId; let item = this.ctx.helper._.find(this.items, data); if (item) return item; item = data; item[this.setting.id] = this.newId; const keyName = itemsPre + item[this.setting.id]; item.children = []; item.is_leaf = true; item.expanded = true; item.visible = true; this.items[keyName] = item; this.datas.push(item); if (parent) { item[this.setting.fullPath] = parent[this.setting.fullPath] + '-' + item[this.setting.id]; item[this.setting.level] = parent[this.setting.level] + 1; item[this.setting.order] = parent.children.length + 1; parent.is_leaf = false; parent.children.push(item); } else { item[this.setting.fullPath] = '' + item[this.setting.id]; item[this.setting.level] = 1; item[this.setting.order] = this.children.length + 1; this.children.push(item); } return item; } sortTreeNodeCustom(field, fun, isResort) { const self = this; const sortNodes = function (nodes) { nodes.sort(function (a, b) { return fun(a[field], b[field]); }); for (const [i, node] of nodes.entries()) { node.order = i + 1; } }; const addSortNodes = function (nodes) { if (!nodes) { return } for (let i = 0; i < nodes.length; i++) { self.nodes.push(nodes[i]); nodes[i].index = self.nodes.length - 1; if (!isResort) { nodes[i].children = self.getChildren(nodes[i]); } sortNodes(nodes[i].children); addSortNodes(nodes[i].children); } }; this.nodes = []; if (!isResort) { this.children = this.getChildren(); } sortNodes(this.children); addSortNodes(this.children); } } class pos { /** * 构造函数 * @param {id|Number, masterId|Number} setting */ constructor (setting) { // 无索引 this.datas = []; // 以key为索引 this.items = {}; // 以分类id为索引的有序 this.ledgerPos = {}; // pos设置 this.setting = setting; } /** * 加载部位明细数据 * @param datas */ loadDatas(datas) { this.datas = datas; this.items = {}; this.ledgerPos = {}; for (const data of this.datas) { const key = itemsPre + data[this.setting.id]; this.items[key] = data; const masterKey = itemsPre + data[this.setting.ledgerId]; if (!this.ledgerPos[masterKey]) { this.ledgerPos[masterKey] = []; } this.ledgerPos[masterKey].push(data); } for (const prop in this.ledgerPos) { this.resortLedgerPos(this.ledgerPos[prop]); } } getLedgerPos(mid) { return this.ledgerPos[itemsPre + mid]; } resortLedgerPos(ledgerPos) { if (ledgerPos instanceof Array) { ledgerPos.sort(function (a, b) { return a.porder - b.porder; }) } } /** * 计算全部 */ calculateAll(fun) { const calcFun = fun ? fun : this.setting.calc; if (!calcFun) return; for (const pos of this.datas) { calcFun(pos); } } getDatas () { return this.datas; } } module.exports = { billsTree, pos, filterTree, filterGatherTree, };