/** * (需使用 decimal.min.js, zh_calc.js) * * 构建pathTree * 可动态加载子节点,要求子节点获取接口按/xxx/get-children定义 * * 所台账结构数据均用到该文件,请勿随意修改。 * @param {Object} setting - 设置 * @returns {PathTree} */ 'use strict'; const itemsPre = 'id_'; class PosData { /** * 构造函数 * @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]); } } /** * 更新数据 * @param datas */ updateDatas(data) { const datas = data instanceof Array ? data : [data]; const result = { create: [], update: [] }, resort = []; for (const d of datas) { const key = itemsPre + d[this.setting.id]; if (!this.items[key]) { this.datas.push(d); this.items[key] = d; const masterKey = itemsPre + d[this.setting.ledgerId]; if (!this.ledgerPos[masterKey]) { this.ledgerPos[masterKey] = []; } this.ledgerPos[masterKey].push(d); result.create.push(d); } else { const pos = this.items[key]; for (const prop in d) { pos[prop] = d[prop]; } result.update.push(pos); } const masterKey = itemsPre + d[this.setting.ledgerId]; if (resort.indexOf(masterKey) === -1) { resort.push(masterKey); } } if (this.setting.calcFun) { for (const u of result.update) { this.setting.calcFun(u); } for (const c of result.create) { this.setting.calcFun(c); } } for (const s of resort) { this.resortLedgerPos(this.ledgerPos[s]); } return result; } /** * 移除数据 * @param datas */ removeDatas(data) { if (!data) { return; } const datas = data instanceof Array ? data : [data]; for (let i = datas.length - 1; i >= 0; i--) { const id = datas[i]; const d = this.getPos(id); this.datas.splice(this.datas.indexOf(d), 1); const key = itemsPre + d[this.setting.id]; delete this.items[key]; const masterKey = itemsPre + d[this.setting.ledgerId]; const range = this.ledgerPos[masterKey]; range.splice(range.indexOf(d), 1); if (range.length === 0) { delete this.ledgerPos[masterKey]; } } } /** * 移除数据 - 根据分类id * @param mid */ removeDatasByMasterId(mid) { const masterKey = itemsPre + mid; const range = this.ledgerPos[masterKey]; if (range) { delete this.ledgerPos[masterKey]; for (const r of range) { this.datas.splice(this.datas.indexOf(r), 1); const key = itemsPre + r[this.setting.id]; delete this.items[key]; } } } getPos(id) { return this.items[itemsPre + id]; } getLedgerPos(mid) { return this.ledgerPos[itemsPre + mid]; } resortLedgerPos(ledgerPos) { const sortRule = this.setting.sort || [['porder', 'asc']]; if (ledgerPos instanceof Array) { ledgerPos.sort(function (a, b) { for (const sr of sortRule) { const iSort = sr[1] === 'asc' ? a[sr[0]] - b[sr[0]] : b[sr[0]] - a[sr[0]]; if (iSort) return iSort; } }) } } /** * 计算全部 */ calculateAll() { if (!this.setting.calcFun) { return; } for (const pos of this.datas) { this.setting.calcFun(pos); } } set sort(sort) { this.setting.sort = sort; for (const key in this.ledgerPos) { this.resortLedgerPos(this.ledgerPos[key]); } } } class StagePosData extends PosData { loadStageData(datas, fieldPre, fields) { if (!datas) { return; } datas = datas instanceof Array ? datas : [datas]; const loadedData = []; for (const data of datas) { let node = this.getPos(data.pid); if (node) { for (const prop of fields) { if (data[prop] !== undefined) { node[fieldPre + prop] = data[prop]; } } if (this.setting.calcFun) { this.setting.calcFun(node); } loadedData.push(node); } } } loadPreStageData(datas) { this.loadStageData(datas, 'pre_', this.setting.updateFields); } loadCurStageData(datas) { this.loadStageData(datas, '', this.setting.updateFields); } } class MasterPosData extends PosData { /** * 构造函数 * @param {id|Number, masterId|Number} setting */ constructor(setting) { super(setting); // 关联索引 this.masterItems = {}; } /** * 加载主数据 * @param datas */ loadDatas(datas) { super.loadDatas(datas); // 清空旧数据 this.masterItems = {}; // minor数据缓存 this.minorData = {}; // 加载全部数据 for (const data of this.datas) { const keyName = itemsPre + data[this.setting.masterId]; this.masterItems[keyName] = data; } } /** * 根据关联id,查找节点 * @param id * @returns {*} */ getMasterItems(id) { return this.masterItems[itemsPre + id]; } /** * 加载关联数据 * * @param {Array|Object}datas - 需要关联的数据 * @param {String} fieldPre - 关联字段前缀(关联结果) * @param {Array} fields - 关联字段 * @returns {Array} */ loadMinorData(datas, fieldSuf, fields) { if (!datas) return; datas = datas instanceof Array ? datas : [datas]; this.minorData[fieldSuf] = datas; const loadedData = []; for (const data of datas) { let node = this.getMasterItems(data[this.setting.minorId]); if (node) { for (const prop of fields) { if (data[prop] !== undefined) { node[prop + fieldSuf] = data[prop]; } } loadedData.push(node); } } return loadedData; } reCalcSumData(fields, fieldSufs) { this.datas.forEach(d => { for (const prop of fields) { delete d['sum_' + prop]; } for (const prop of fields) { for (const s of fieldSufs) { if (d[prop + s] !== undefined) { d['sum_'+ prop] = ZhCalc.add(d['sum_' + prop], d[prop + s]); } } } }); } } const createNewPathTree = function (type, setting) { class BaseTree { /** * 构造函数 */ constructor(setting) { const self = this; // 无索引 this.datas = []; // 以key为索引indexedDB this.items = {}; // 以排序为索引 this.nodes = []; // 根节点 this.children = []; // 树设置 this.setting = setting; if (!this.setting.isLeaf) this.setting.isLeaf = 'is_leaf'; if (!this.setting.fullPath) this.setting.fullPath = 'full_path'; this.hasMark = false; if (this.setting.markExpandKey) { const markStr = getLocalCache(this.setting.markExpandKey); const markData = markStr ? markStr.split('|') : ['', '']; this.hasMark = markData[0] === this.setting.markExpandSubKey; this.markExpand = this.hasMark && markData[1] ? _.map(markData[1].split(','), _.toInteger) : []; } else if (this.setting.markFoldKey) { const markStr = getLocalCache(this.setting.markFoldKey); const markData = markStr ? markStr.split('|') : ['', '']; this.hasMark = markData[0] === this.setting.markFoldSubKey; this.markFold = this.hasMark && markData[1] ? _.map(markData[1].split(','), _.toInteger) : []; } // if (this.setting.treeCacheKey) { // localforage.getItem(this.setting.treeCacheKey).then(function (v) { // self.markFold = v && v.markFold ? v.markFold : []; // }); // } } /** * 树结构根据显示排序 */ 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 { self.sortByOrder(nodes[i].children); } addSortNodes(nodes[i].children); } }; this.nodes = []; if (!isResort) { this.children = this.getChildren(); } else { this.sortByOrder(this.children); } addSortNodes(this.children); } sortByOrder(datas) { const setting = this.setting; datas.sort((a, b) => { return a[setting.order] - b[setting.order]; }); } sortByLevel(datas) { const setting = this.setting; datas.sort((a, b) => { return a[setting.level] - b[setting.level]; }); } sortByLevelConverse(datas) { const setting = this.setting; datas.sort((a, b) => { return b[setting.level] - a[setting.level]; }); } /** * 加载数据(初始化), 并给数据添加部分树结构必须数据 * @param datas */ loadDatas(datas) { const self = this; // 清空旧数据 this.items = {}; this.nodes = []; this.datas = []; this.children = []; // 加载全部数据 this.sortByLevel(datas); const setting = this.setting; for (const data of datas) { const keyName = itemsPre + data[this.setting.id]; if (this.items[keyName]) continue; const item = JSON.parse(JSON.stringify(data)); item.children = []; item.expanded = true; item.visible = true; if (item[setting.pid] === setting.rootId) { this.children.push(item); } else { const parent = this.getParent(item); if (!parent) continue; parent.children.push(item); } this.items[keyName] = item; this.datas.push(item); } this.sortByOrder(this.children); this.sortTreeNode(true); if (this.hasMark) { if (this.setting.markExpandKey) { this.expandByCustom(node => { return self.markExpand.indexOf(node[self.setting.id]) >= 0; }); } else if (this.setting.markFoldKey) { this.expandByCustom(function (node) { return self.markFold.indexOf(node[self.setting.id]) === -1; }); } } else { if (this.setting.autoExpand >= 0) { this.expandByLevel(this.setting.autoExpand); for (const node of this.nodes) { this._markExpandFold(node); } this._saveMarkExpandFold(); } } } loadFilter(select, filterType = 'access') { const defaultValue = filterType === 'access' ? true : false; this.select = select ? select.split(',') : []; for (const d of this.datas) { d.filter = defaultValue; } const parents = []; for (const s of this.select) { const node = this.getItems(s); if (!node) continue; node.filter = !defaultValue; const posterity = this.getPosterity(node); for (const p of posterity) { p.filter = !defaultValue; } parents.push(...this.getAllParents(node)); } this.sortByLevelConverse(parents); for (const parent of parents) { if (!parent.children || parent.children.length === 0) continue; parent.filter = !parent.children.find(x => { return !x.filter }); } for (const node of this.nodes) { const parent = this.getParent(node); node.visible = parent ? (parent.expanded && parent.visible && !node.filter) : !node.filter; } } getItemsByIndex(index) { return this.nodes[index]; } /** * 根据id获取树结构节点数据 * @param {Number} id * @returns {Object} */ getItems(id) { return this.items[itemsPre + id]; }; getNodeIndex(node) { return this.nodes.indexOf(node); } /** * 查找node的parent * @param {Object} node * @returns {Object} */ getParent(node) { return this.getItems(node[this.setting.pid]); }; getTopParent(node) { const parents = this.getAllParents(node); this.sortByLevel(parents); return parents[0]; }; getAllParents(node) { const parents = []; if (!node) return parents; if (node[this.setting.fullPath] && node[this.setting.fullPath] !== '') { const parentIds = node[this.setting.fullPath].split('-'); parentIds.length = parentIds.length - 1; for (const id of parentIds) { if (id !== node[this.setting.id]) { parents.push(this.getItems(id)); } } } else { let vP = this.getParent(node); while (vP) { parents.push(vP); vP = this.getParent(vP); } } return parents; } /** * 查找node的前兄弟节点 * @param node * @returns {*} */ getPreSiblingNode(node) { if (!node) return null; const parent = this.getParent(node); const siblings = parent ? parent.children : this.children; const index = siblings.indexOf(node); return (index > 0) ? siblings[index - 1] : null; } /** * 查找node的后兄弟节点 * @param node * @returns {*} */ getNextSiblingNode(node) { const parent = this.getParent(node); const siblings = parent ? parent.children : this.children; const index = siblings.indexOf(node); if (index >= 0 && index < siblings.length - 1) { return siblings[index + 1]; } else { return null; } } /** * 根据path查找完整节点 * @param {Number} path */ getFullPathNodes(path) { const self = this, ids = path.split('-'); if (ids.length > 0) { return this.nodes.filter((x) => { return ids.indexOf('' + x[self.setting.id]) >= 0; }); } else { return []; } }; /** * 查询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; }); this.sortByOrder(children); return children; }; /** * 递归方式 查询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) { const self = this; let posterity; if (node[self.setting.fullPath] !== undefined && node[self.setting.fullPath] !== '') { const reg = new RegExp('^' + node[self.setting.fullPath] + '-'); posterity = this.datas.filter(function (x) { return reg.test(x[self.setting.fullPath]); }); } else { posterity = this._recursiveGetPosterity(node); } posterity.sort(function (x, y) { return self.getNodeIndex(x) - self.getNodeIndex(y); }); return posterity; }; /** * 递归方式 查询node的已下载的全部后代 (兼容full_path不存在的情况) * @param node * @returns {*} * @private */ _recursiveGetLeafPosterity(node) { let posterity = node.children.filter(x => { return !x.children && x.children.length === 0; }); for (const c of node.children) { posterity = posterity.concat(this._recursiveGetLeafPosterity(c)); } return posterity; }; /** * 查询node的已下载的全部后代 * @param {Object} node * @returns {Array} */ getLeafPosterity(node) { const self = this; let posterity; if (node[self.setting.fullPath] !== '') { const reg = new RegExp('^' + node[self.setting.fullPath] + '-'); posterity = this.datas.filter(function (x) { return reg.test(x[self.setting.fullPath]) && x.is_leaf; }); } else { posterity = this._recursiveGetLeafPosterity(node); } posterity.sort(function (x, y) { return self.getNodeIndex(x) - self.getNodeIndex(y); }); return posterity; }; /** * 查询node是否是父节点的最后一个子节点 * @param {Object} node * @returns {boolean} */ isLastSibling(node) { const siblings = this.getChildren(this.getParent(node)); return (siblings && siblings.length > 0) ? node[this.setting.order] === siblings[siblings.length - 1][this.setting.order] : false; }; /** * 查询node是否是父节点的最后一个可见子节点 * @param {Object} node * @returns {boolean} */ isLastViewSibling(node) { const siblings = (this.getChildren(this.getParent(node))).filter(x => { return !x.filter }); return (siblings && siblings.length > 0) ? node[this.setting.order] === siblings[siblings.length - 1][this.setting.order] : false; }; /** * 提取节点key和索引数据 * @param {Object} node - 节点 * @returns {key} */ getNodeKeyData(node) { const data = {}; for (const key of this.setting.keys) { data[key] = node[key]; } return data; }; /** * 得到树结构构成id * @param node * @returns {*} */ getNodeKey(node) { return node[this.setting.id]; }; _markExpandFold(node) { if (this.setting.markExpandKey && this.setting.markExpandSubKey) { if (node.expanded) { if (this.markExpand.indexOf(node[this.setting.id]) === -1) this.markExpand.push(node[this.setting.id]); } else { if (this.markExpand.indexOf(node[this.setting.id]) >= 0) this.markExpand.splice(this.markExpand.indexOf(node[this.setting.id]), 1); } } else if (this.setting.markFoldKey && this.setting.markFoldSubKey) { if (!node.expanded) { if (this.markFold.indexOf(node[this.setting.id]) === -1) this.markFold.push(node[this.setting.id]); } else { if (this.markFold.indexOf(node[this.setting.id]) >= 0) this.markFold.splice(this.markFold.indexOf(node[this.setting.id]), 1); } } } _saveMarkExpandFold() { if (this.setting.markExpandKey && this.setting.markExpandSubKey) { setLocalCache(this.setting.markExpandKey, this.setting.markExpandSubKey + '|' + this.markExpand.join(',')); } else if (this.setting.markFoldKey && this.setting.markFoldSubKey) { setLocalCache(this.setting.markFoldKey, this.setting.markFoldSubKey + '|' + this.markFold.join(',')); } // if (this.setting.treeCacheKey) { // localforage.setItem(this.setting.treeCacheKey, { // markFold: this.markFold, // time: new Date(), // }); // } } /** * 刷新子节点是否可见 * @param {Object} node * @private */ _refreshChildrenVisible(node) { if (!node.children) { node.children = this.getChildren(node); } if (node.children && node.children.length > 0) { for (const child of node.children) { child.visible = node.expanded && node.visible && !child.filter; this._refreshChildrenVisible(child); } } }; /** * 设置节点是否展开, 并控制子节点可见 * @param {Object} node * @param {Boolean} expanded */ setExpanded(node, expanded) { node.expanded = expanded; this._markExpandFold(node); this._refreshChildrenVisible(node); this._saveMarkExpandFold(); }; /** * 递归 设置节点展开状态 * @param {Array} nodes - 需要设置状态的节点 * @param {Object} parent - nodes的父节点 * @param {Function} checkFun - 判断节点展开状态的方法 * @private */ _recursiveExpand(nodes, parent, checkFun) { for (const node of nodes) { const expanded = checkFun(node); if (node.expanded !== expanded) { node.expanded = expanded; this._markExpandFold(node); } node.visible = parent ? (parent.expanded && parent.visible && !node.filter) : !node.filter; this._recursiveExpand(node.children, node, checkFun); } } /** * 自定义展开规则 * @param checkFun */ expandByCustom(checkFun) { this._recursiveExpand(this.children, null, checkFun); this._saveMarkExpandFold(); } /** * 展开到第几层 * @param {Number} level - 展开层数 */ expandByLevel(level) { const field = this.setting.level; this.expandByCustom(function (n) { return n[field] < level; }); } /** * 自动展开节点node * @param node * @returns {*} */ autoExpandNode(node) { const parents = this.getAllParents(node); const reload = []; for (const p of parents) { if (!p.expanded) { reload.push(p); this.setExpanded(p, true); } } return reload; } /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ _updateData(datas) { datas = datas instanceof Array ? datas : [datas]; let loadedData = []; for (const data of datas) { let node = this.getItems(data[this.setting.id]); if (node) { for (const prop in data) { if (data[prop] !== undefined && data[prop] !== node[prop]) { if (prop === this.setting.pid) { loadedData.push(this.getItems(node[this.setting.pid])); loadedData.push(this.getItems(data[this.setting.pid])); } if (prop === this.setting.order) { loadedData = loadedData.concat(this.getPosterity(node)); } node[prop] = data[prop]; } } loadedData.push(node); } } loadedData = _.uniq(loadedData); for (const node of loadedData) { if (node) { node.children = this.getChildren(node); node.expanded = node.children.length === 0 ? true : node.children[0].visible; } else { this.children = this.getChildren(null); } } this.sortTreeNode(true); return loadedData; }; /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ _loadData(datas) { datas = datas instanceof Array ? datas : [datas]; const loadedData = [], resortData = []; for (const data of datas) { let node = this.getItems(data[this.setting.id]); if (node) { const parent = this.getItems(node[this.setting.pid]); for (const prop in data) { if (data[prop] !== undefined && data[prop] !== node[prop]) { node[prop] = data[prop]; if (parent && resortData.indexOf(parent) === -1) { resortData.push(parent); } } } loadedData.push(node); } else { const keyName = itemsPre + data[this.setting.id]; const node = JSON.parse(JSON.stringify(data)); this.items[keyName] = node; this.datas.push(node); node.expanded = true; node.visible = true; loadedData.push(node); if (resortData.indexOf(node) === -1) { resortData.push(node); } const parent = this.getItems(node[this.setting.pid]); if (parent && resortData.indexOf(parent) === -1) { resortData.push(parent); } else { resortData.push(this.setting.rootId); } } } for (const node of resortData) { if (node && node !== this.setting.rootId) { node.children = this.getChildren(node); } else { this.children = this.getChildren(null); } } this.sortTreeNode(true); for (const node of loadedData) { if (!node.expanded) { this.setExpanded(node, true); } } return loadedData; }; /** * 清理数据(动态) * @param datas * @private */ _freeData(datas) { datas = datas instanceof Array ? datas : [datas]; const freeDatas = []; const removeArrayData = function (array, data) { const index = array.indexOf(data); array.splice(index, 1); }; for (const data of datas) { const node = this.getItems(data[this.setting.id]); if (node) { freeDatas.push(node); node.deleteIndex = this.nodes.indexOf(node); delete this.items[itemsPre + node[this.setting.id]]; if (node[this.setting.pid] !== this.setting.rootId) { const parent = this.getItems(node[this.setting.pid]); if (parent) { removeArrayData(parent.children, node); } } else { removeArrayData(this.children, node); } removeArrayData(this.datas, node); } } for (const node of freeDatas) { removeArrayData(this.nodes, node); } return freeDatas; }; /** * 加载需展开的数据 * @param {Array} datas * @returns {Array} * @private */ _loadExpandData(datas) { datas = datas instanceof Array ? datas : [datas]; const loadedData = [], existData = [], expandData = [], resortData = []; for (const data of datas) { let node = this.getItems(data[this.setting.id]); if (node) { existData.push(node); } else { const keyName = itemsPre + data[this.setting.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); if (resortData.indexOf(node) === -1) { resortData.push(node); } const parent = this.getItems(node[this.setting.pid]); if (parent && resortData.indexOf(parent) === -1) { resortData.push(parent); } } } for (const node of resortData) { node.children = this.getChildren(node); } this.sortTreeNode(true); for (const node of loadedData) { if (!node.expanded) { this.setExpanded(node, true); } } for (const node of existData) { const parent = this.getItems(node[this.setting.pid]); if (expandData.indexOf(parent) === -1) { expandData.push(parent); if (!parent.expanded) { this.setExpanded(parent, true); } } if (!node.expanded) { this.setExpanded(node, true); } } return [loadedData, expandData]; }; /** * 因为提交其他数据,引起的树结构数据更新,调用该方法 * * @param data - 更新的数据 {update, create, delete} * @returns {{}} */ loadPostData(data) { const result = {}; if (data.delete) { result.delete = this._freeData(data.delete); } if (data.create) { result.create = this._loadData(data.create); } if (data.update) { result.update = this._updateData(data.update); } return result; } /** * 加载子节点 * @param {Object} node * @param {function} callback */ loadChildren(node, callback) { if (this.setting.url !== '') { const self = this; postData(this.setting.url, { postType: 'load-child', id: this.getNodeKeyData(node) }, function (data) { self._loadData(data); callback(); }); } }; _getDefaultNodeData(node) { const result = {}; for (const prop in node) { if (['children', 'visible', 'expanded'].indexOf(prop) >= 0) continue; result[prop] = node[prop]; } return result; } getDefaultData(node) { if (node instanceof Array) { const arr = []; for (const n of node) { arr.push(this._getDefaultNodeData(n)); } return arr; } else { this._getDefaultNodeData(node); } } checkParent(node, field = 'check') { const parent = this.getParent(node); return parent ? (parent[field] ? parent[field] : this.checkParent(parent, field)) : false; } checkChildren(node, field = 'check') { for (const child of node.children) { if (child[field]) { return true; } else if (this.checkChildren(child, field)) { return true; } } return false; } } class MeasureTree extends BaseTree { addData(datas) { const loadedData = []; for (const data of datas) { let node = this.getItems(data[this.setting.id]); if (node) { for (const prop in data) { if (data[prop] !== undefined) { node[prop] = data[prop]; } } loadedData.push(node); } else { const keyName = itemsPre + data[this.setting.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 = node.children; if (!node.expanded && children.length > 0) { node.expanded = true; this._refreshChildrenVisible(node); } } return loadedData; } removeData(datas) { this.sortByLevel(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[this.setting.id]); if (node && this.getChildren(node).length === 0) { delete this.items[itemsPre + node[this.setting.id]]; if (node[this.setting.pid] !== this.setting.rootId) { const parent = this.items[itemsPre + node[this.setting.pid]]; removeArrayData(parent.children, node); } removeArrayData(this.datas, node); removeArrayData(this.nodes, node); } } }; loadLeafData(data) { const datas = data instanceof Array ? data : [data]; for (const d of datas) { let node = this.getItems(d[this.setting.id]); if (node && node[this.setting.isLeaf]) { for (const prop in d) { if (data[prop] !== undefined) { node[prop] = d[prop]; } } } } }; } class FxTree 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; } /** * 展开至最底层项目节 */ expandToLeafXmj() { const self = this; this.expandByCustom(function (node) { if (node.b_code && node.b_code !== '') { return false; } else { return !self.isLeafXmj(node); } }) } /** * 展开至计算项 */ expandByCalcFields() { const self = this; this.expandByCustom(function (node) { for (const field of self.setting.calcFields) { if (node[field]) { return true; } } return false; }) } checkCodeType() { for (const node of this.nodes) { if (!node.code) continue; if (node.code.indexOf('-') >= 0) { return '07'; } else if (node.code.length >= 5) { const num = _.toNumber(node.code); if (num && num > 10000) return '18'; } } return '18'; } getCodeSplit() { return this.checkCodeType() === '07' ? '-' : '0'; } initNodeData(field, defaultValue, calcFun) { if (!field || !calcFun) return; const initNode = function (node) { if (node[field] === undefined) node[field] = defaultValue; if (node.children && node.children.length > 0) { const values = []; for (const child of node.children) { initNode(child); if (values.indexOf(child[field]) < 0) values.push(child[field]); } node[field] = calcFun(values, defaultValue); } }; for (const node of this.children) { initNode(node); } } } class LedgerTree extends FxTree { /** * * @param parent * @param node * @private */ _getNodesParents(parents, nodes) { for (const node of nodes) { const parent = this.getParent(node); if (parent) { const paths = this.getFullPathNodes(parent[this.setting.fullPath]); for (const p of paths) { if (parents.indexOf(p) === -1) { parents.push(p); } } } if (this.getItems(node.ledger_id) && node.children.length > 0) { parents.push(node); } } } _getReCalcNodes(reCalcNodes, nodes) { for (const node of nodes) { const parent = this.getParent(node); if (parent) { const paths = this.getFullPathNodes(parent[this.setting.fullPath]); for (const p of paths) { if (reCalcNodes.indexOf(p) === -1) { reCalcNodes.push(p); } } } // 最底层项目节,也需要计算 //if (this.getItems(node.ledger_id) && node.children.length > 0) { reCalcNodes.push(node); //} } } /** * 因为提交其他数据,引起的树结构数据更新,调用该方法 * * @param data - 更新的数据 {update, create, delete} * @returns {{}} */ loadPostData(data) { const result = {}, reCalcNodes = []; if (!data) return result; if (data.delete) { result.delete = this._freeData(data.delete); this._getReCalcNodes(reCalcNodes, result.delete); } if (data.create) { result.create = this._loadData(data.create); this._getReCalcNodes(reCalcNodes, result.create); } if (data.update) { result.update = this._updateData(data.update); this._getReCalcNodes(reCalcNodes, result.update); } this.sortByLevelConverse(reCalcNodes); for (const node of reCalcNodes) { treeCalc.calculateNode(this, node, this.setting.calcFields, this.setting.calcFun); } result.update = result.update ? result.update.concat(reCalcNodes) : reCalcNodes; return result; } } class ReviseTree extends LedgerTree { constructor (setting) { super(setting); this.price = []; } checkNodeUsed(node, pos) { if (node.children && node.children.length > 0) { for (const child of node.children) { const used = this.checkNodeUsed(child, pos); if (used) return used; } } else { if (node.used) return node.used; const posRange = pos.getLedgerPos(node.id); if (posRange && posRange.length > 0) { for (const p of posRange) { if (p.used) return p.used; } } } return false; } loadRevisePrice(price, decimal) { this.decimal = decimal; this.price = price || []; this.rela_price = []; this.common_price = []; this.price.forEach(x => { if (x.rela_lid) { x.rela_lid = x.rela_lid.split(','); this.rela_price.push(x); } else { this.common_price.push(x); } }); } checkRevisePrice(d) { if (d.settle_status) return false; if (!this.price || this.price.length === 0) return false; const setting = this.setting; const pid = this.getAllParents(d).map(x => { return x[setting.id] + ''; }); const checkRela = function(rela_lid) { if (!rela_lid || rela_lid.length === 0) return false; for (const lid of rela_lid) { if (pid.indexOf(lid) >= 0) return true; } return false; }; let p = this.rela_price.find(x => { return x.b_code === d.b_code && ((!x.name && !d.name) || x.name === d.name) && ((!x.unit && !d.unit) || x.unit === d.unit) && checkZero(x.org_price - d.unit_price) && checkRela(x.rela_lid); }); if (!p) p = this.common_price.find(x => { return x.b_code === d.b_code && ((!x.name && !d.name) || x.name === d.name) && ((!x.unit && !d.unit) || x.unit === d.unit) && checkZero(x.org_price - d.unit_price); }); if (!p) return false; d.org_price = p.org_price; d.unit_price = p.new_price; d.deal_tp = ZhCalc.mul(d.deal_qty, d.unit_price, this.decimal.tp); d.sgfh_tp = ZhCalc.mul(d.sgfh_qty, d.unit_price, this.decimal.tp); d.sjcl_tp = ZhCalc.mul(d.sjcl_qty, d.unit_price, this.decimal.tp); d.qtcl_tp = ZhCalc.mul(d.qtcl_qty, d.unit_price, this.decimal.tp); d.total_price = ZhCalc.mul(d.quantity, d.unit_price, this.decimal.tp); return true; } loadDatas(datas) { super.loadDatas(datas); if (this.price.length > 0) { for (const d of this.datas) { if (d.children && d.children.length > 0) continue; if (!d.b_code) continue; this.checkRevisePrice(d); } } } loadPostReivsePrice(data) { let result = false; if (!this.price) return result; for (const d of data) { if (!d.is_leaf || !d.b_code) continue; if (this.checkRevisePrice(d)) result = true; } return result; } loadPostData(data) { const setting = this.setting; const result = {}, reCalcNodes = []; if (!data) return result; if (data.delete) { result.delete = this._freeData(data.delete); this._getReCalcNodes(reCalcNodes, result.delete); } if (data.create) { result.create = this._loadData(data.create); this.loadPostReivsePrice(result.create); this._getReCalcNodes(reCalcNodes, result.create); } if (data.update) { result.update = this._updateData(data.update); this.loadPostReivsePrice(result.update); this._getReCalcNodes(reCalcNodes, result.update); } this.sortByLevelConverse(reCalcNodes); for (const node of reCalcNodes) { treeCalc.calculateNode(this, node, this.setting.calcFields, this.setting.calcFun); } result.update = result.update ? result.update.concat(reCalcNodes) : reCalcNodes; return result; } } class StageTree extends FxTree { /** * 构造函数 */ constructor(setting) { super(setting); // stage关联索引 this.stageItems = {}; } _loadLockedNodes(ids){ this.Locked = ids || []; for (const f of this.Locked) { f.locked_ledger_id = f.ass_ledger_id ? f.ass_ledger_id.split(',') : (f.audit_ledger_id ? f.audit_ledger_id.split(',') : []); for (const id of f.ass_ledger_id) { const node = this.getItems(id); node.locked = true; const posterity = this.getPosterity(node); for (const pn of posterity) { pn.locked = true; pn.lock = true; } } } } /** * 加载数据(初始化), 并给数据添加部分树结构必须数据 * @param datas */ loadDatas(datas, locked) { super.loadDatas(datas); // 清空旧数据 this.stageItems = {}; // 加载全部数据 for (const data of this.datas) { const keyName = itemsPre + data[this.setting.stageId]; this.stageItems[keyName] = data; } this._loadLockedNodes(locked) } getStageItems(id) { return this.stageItems[itemsPre + id]; } loadStageData(datas, fieldPre, fields) { datas = datas instanceof Array ? datas : [datas]; const loadedData = []; for (const data of datas) { let node = this.getStageItems(data.lid); if (node) { for (const prop of fields) { if (data[prop] !== undefined) { node[fieldPre + prop] = data[prop]; } } loadedData.push(node); } } } loadPreStageData(datas) { this.loadStageData(datas, 'pre_', this.setting.updateFields); } loadCurStageData(datas) { this.loadStageData(datas, '', this.setting.updateFields); } /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ _updateData(datas) { datas = datas instanceof Array ? datas : [datas]; let loadedData = []; for (const data of datas) { let node = this.getItems(data[this.setting.id]); if (node) { for (const prop in data) { if (prop === this.setting.pid && data[prop] !== node[prop]) { } if (data[prop] !== undefined && data[prop] !== node[prop]) { if (prop === this.setting.pid) { loadedData.push(this.getItems(node[this.setting.pid])); loadedData.push(this.getItems(data[this.setting.pid])); } node[prop] = data[prop]; } } loadedData.push(node); } } loadedData = _.uniq(loadedData); for (const node of loadedData) { node.children = this.getChildren(node); node.expanded = node.children.length === 0 ? true : node.children[0].visible; } this.sortTreeNode(true); return loadedData; }; /** * 加载数据(动态),只加载不同部分 * @param {Array} datas * @return {Array} 加载到树的数据 * @privateA */ _updateStageData(datas) { datas = datas instanceof Array ? datas : [datas]; const loadedData = []; for (const data of datas) { let node = this.getStageItems(data.lid); if (node) { for (const prop of this.setting.updateFields) { if (data[prop] !== undefined) { node[prop] = data[prop]; } } loadedData.push(node); } } return loadedData; }; /** * * @param parent * @param node * @private */ _getNodesParents(parents, nodes) { for (const node of nodes) { const parent = this.getParent(node); if (parent) { const paths = this.getFullPathNodes(parent[this.setting.fullPath]); for (const p of paths) { if (parents.indexOf(p) === -1) { parents.push(p); } } } if (node.children && node.children.length > 0) { parents.push(node); } } } _updateDgnData(datas) { datas = datas instanceof Array ? datas : [datas]; let loadedData = []; for (const data of datas) { let node = this.getStageItems(data.id); if (node) { for (const prop in data) { if (data[prop] !== undefined && data[prop] !== node[prop]) { node[prop] = data[prop]; } } loadedData.push(node); } } return loadedData; } /** * 提交数据至后端,返回的前端树结构应刷新的部分 * StageTree仅有更新CurStage部分,不需要增删 * * @param data - 需要更新的数据 * @returns {Array} - 界面需要刷新的数据 */ loadPostStageData(data) { let result, parents = []; if (data.bills) { result = this._updateData(data.bills); this._getNodesParents(parents, result); } if (data.curStageData) { result = this._updateStageData(data.curStageData); this._getNodesParents(parents, result); } if (data.dgn) { const dgnResult = this._updateDgnData(data.dgn); result = result ? result.concat(dgnResult) : dgnResult; } result = result ? result.concat(parents) : parents; this.sortByLevelConverse(result); for (const node of result) { treeCalc.calculateNode(this, node); } return result; } getLockedInfo(node) { const ownerNodes = this.getAllParents(node); const lockedInfo = []; for (const on of ownerNodes) { const filter = this.Locked.filter(x => { return x.ass_ledger_id.indexOf(on.ledger_id + '') >= 0; }); lockedInfo.push(...filter); } return lockedInfo; } } class MasterTree extends FxTree { /** * 构造函数 */ constructor(setting) { super(setting); // 关联索引 this.masterItems = {}; } /** * 加载数据(初始化), 并给数据添加部分树结构必须数据 * @param datas */ loadDatas(datas) { super.loadDatas(datas); // 清空旧数据 this.masterItems = {}; // minor数据缓存 this.minorData = {}; // 加载全部数据 for (const data of this.datas) { const keyName = itemsPre + data[this.setting.masterId]; this.masterItems[keyName] = data; } } /** * 根据关联id,查找节点 * @param id * @returns {*} */ getMasterItems(id) { return this.masterItems[itemsPre + id]; } /** * 加载关联数据 * * @param {Array|Object}datas - 需要关联的数据 * @param {String} fieldPre - 关联字段前缀(关联结果) * @param {Array} fields - 关联字段 * @returns {Array} */ loadMinorData(datas, fieldSuf, fields, calcFields) { for (const cf of calcFields) { this.setting.calcFields.push(cf + fieldSuf); } if (!datas) return; datas = datas instanceof Array ? datas : [datas]; this.minorData[fieldSuf] = datas; const loadedData = []; for (const data of datas) { let node = this.getMasterItems(data[this.setting.minorId]); if (node) { for (const prop of fields) { if (data[prop] !== undefined) { node[prop + fieldSuf] = data[prop]; } } loadedData.push(node); } } return loadedData; } reCalcSumData(fields, fieldSufs) { this.datas.forEach(d => { for (const prop of fields) { delete d['sum_' + prop]; } for (const prop of fields) { for (const s of fieldSufs) { if (d[prop + s] !== undefined) { d['sum_'+ prop] = ZhCalc.add(d['sum_' + prop], d[prop + s]); } } } }); } } class FilterTree extends BaseTree { clearDatas() { this.items = {}; this.nodes = []; this.datas = []; this.children = []; } 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[setting.pid] === 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 GatherTree 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 = _.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[self.setting.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 CompareTree extends FxTree { constructor(setting) { super(setting); this._newId = 1; } get newId() { return this._newId++; } findCompareNode(node, parent) { if (this.setting.findNode) { return this.setting.findNode(this, node, parent); } else { const siblings = parent ? parent.children : this.children; return siblings.find(function (x) { return node.b_code ? x.b_code === node.b_code && x.name === node.name && x.unit === node.unit && x.unit_price === node.unit_price : x.code === node.code && x.name === node.name; }); } } loadCompareNode(source, node, parent, loadFun) { let cur = this.findCompareNode(node, parent); if (!cur) { const siblings = parent ? parent.children : this.children; const id = this.newId; cur = { children: [], pos: [], code: node.code, b_code: node.b_code, name: node.name, unit: node.unit, unit_price: node.unit_price, }; cur[this.setting.id] = id; cur[this.setting.pid] = parent ? parent[this.setting.id] : this.setting.rootId; cur[this.setting.fullPath] = parent ? parent[this.setting.fullPath] + '-' + id : '' + id; cur[this.setting.level] = parent ? parent[this.setting.level] + 1 : 1; cur[this.setting.order] = siblings.length + 1; siblings.push(cur); this.datas.push(cur); } loadFun(cur, node, source); for (const c of node.children) { this.loadCompareNode(source, c, cur, loadFun); } } generateSortNodes() { const self = this; const addSortNode = function (node) { self.nodes.push(node); for (const c of node.children) { addSortNode(c); } } this.nodes = []; for (const n of this.children) { addSortNode(n); } } loadCompareTree(data, loadFun) { for (const c of data.billsTree.children) { this.loadCompareNode(data, c, null, loadFun); } } calculateDiffer() { if (this.setting.calcDiffer) { for (const d of this.datas) { this.setting.calcDiffer(d); } } } loadCompareData(data1, data2) { this.loadCompareTree(data1, this.setting.loadInfo1); this.loadCompareTree(data2, this.setting.loadInfo2); for (const d of this.datas) { d.is_leaf = d.children.length === 0; d.expanded = true; d.visible = true; this.items[itemsPre + d[this.setting.id]] = d; } this.generateSortNodes(); this.calculateDiffer(); if (this.setting.afterLoad) this.setting.afterLoad(this); } } class TreeGatherTree extends FxTree { constructor(setting) { super(setting); this._newId = 1; } get newId() { return this._newId++; } loadGatherNode(node, parent, index, loadFun) { const siblings = parent ? parent.children : this.children; let cur = siblings.find(function (x) { return node.b_code ? x.b_code === node.b_code && x.name === node.name && x.unit === node.unit && x.unit_price === node.unit_price : x.code === node.code && x.name === node.name; }); if (!cur) { const id = this.newId; cur = { id: id, pid: parent ? parent.id : this.setting.rootId, full_path: parent ? parent.full_path + '-' + id : '' + id, level: parent ? parent.level + 1 : 1, order: siblings.length + 1, children: [], code: node.code, b_code: node.b_code, name: node.name, unit: node.unit, unit_price: node.unit_price, }; siblings.push(cur); this.datas.push(cur); } loadFun(cur, node, index); for (const c of node.children) { this.loadGatherNode(c, cur, index, loadFun); } } generateSortNodes() { const self = this; const addSortNode = function (node) { self.nodes.push(node); for (const c of node.children) { addSortNode(c); } }; this.nodes = []; for (const n of this.children) { addSortNode(n); } } loadGatherTree(data, index, loadFun) { for (const c of data.billsTree.children) { this.loadGatherNode(c, null, index, loadFun); } // todo load Pos Data; } calculateSum() { if (this.setting.calcSum) { for (const d of this.datas) { this.setting.calcSum(d, this.count); } } } loadGatherData(datas) { this.count = datas.length; for (const [i, data] of datas.entries()) { this.loadGatherTree(data, i+1, this.setting.loadInfo); } for (const d of this.datas) { d.is_leaf = d.children.length === 0; d.expanded = true; d.visible = true; this.items[itemsPre + d[this.setting.id]] = d; } this.generateSortNodes(); this.calculateSum(); } } class FinalTree extends BaseTree { constructor(setting) { super(setting); this._newId = 1; } get newId() { return this._newId++; } loadNode(node, parent, loadFun) { if (node.b_code) return; const siblings = parent ? parent.children : this.children; let cur = siblings.find(function (x) { return x.code === node.code && x.name === node.name; }); if (!cur) { const id = this.newId; cur = { id: id, pid: parent ? parent.id : this.setting.rootId, full_path: parent ? parent.full_path + '-' + id : '' + id, level: parent ? parent.level + 1 : 1, order: siblings.length + 1, children: [], code: node.code, name: node.name, unit: node.unit, }; siblings.push(cur); this.datas.push(cur); } loadFun(cur, node); for (const c of node.children) { this.loadNode(c, cur, loadFun); } } loadTree(tree, loadFun) { for (const node of tree.children) { this.loadNode(node, null, loadFun); } } generateSortNodes() { const self = this; const addSortNode = function (node) { self.nodes.push(node); for (const c of node.children) { addSortNode(c); } }; this.nodes = []; for (const n of this.children) { addSortNode(n); } } afterLoad(fun) { for (const d of this.datas) { fun && fun(d); d.is_leaf = d.children.length === 0; d.expanded = true; d.visible = true; this.items[itemsPre + d[this.setting.id]] = d; } this.generateSortNodes(); } clearFinal() { this.datas = this.datas.filter(x => { return !!x.base; }); this.datas.forEach(x => { delete x.total_price; delete x.dgn_qty1; delete x.dgn_qty2; delete x.dgn_qty; delete x.dgn_price; delete x.final_dgn_qty1; delete x.final_dgn_qty2; delete x.final_dgn_qty; delete x.final_dgn_price; delete x.final_tp; delete x.grow_dgn_qty1; delete x.grow_dgn_qty2; delete x.grow_dgn_qty; delete x.grow_tp; }); this.loadDatas(this.datas); } resortChildrenByCustom(fun) { for (const n of this.nodes) { if (n.children && n.children.length > 1) { n.children.sort(fun); n.children.forEach((x, y) => { x.order = y + 1; }); } } this.generateSortNodes(); } } if (type === 'base') { return new BaseTree(setting); } else if (type === 'fx') { return new FxTree(setting); } else if (type === 'stage') { return new StageTree(setting); } else if (type === 'ledger') { return new LedgerTree(setting); } else if (type === 'revise') { return new ReviseTree(setting); } else if (type === 'measure') { return new MeasureTree(setting); } else if (type === 'master') { return new MasterTree(setting); } else if (type === 'filter') { return new FilterTree(setting); } else if (type === 'gather') { return new GatherTree(setting); } else if (type === 'compare') { return new CompareTree(setting); } else if (type === 'tree-gather') { return new TreeGatherTree(setting); } else if (type === 'final') { return new FinalTree(setting); } }; const createAncillaryGcl = function (setting) { class AncillaryGcl { /** * 构造函数 * @param {id|Number, masterId|Number} setting */ constructor(setting) { this.itemPre = 'id_'; // 无索引 this.datas = []; // 以key为索引 this.items = {}; // 以分类id为索引的有序 this.masterIndex = {}; // 设置 this.setting = setting; } resortPart(partData) { const sortRule = this.setting.sort || [['g_order', 'asc']]; if (partData instanceof Array) { partData.sort(function (a, b) { for (const sr of sortRule) { const iSort = sr[1] === 'asc' ? a[sr[0]] - b[sr[0]] : b[sr[0]] - a[sr[0]]; if (iSort) return iSort; } }) } } filterPart(partData) { const check = this._filter; partData.forEach(x => { x.visible = true; if (check) { for (const prop in check) { if (x[prop] !== check[prop]) x.visible = false; } } }); } /** * 加载数据 * @param datas */ loadDatas(datas) { this.datas = datas; this.items = {}; this.masterIndex = {}; for (const data of this.datas) { const key = this.itemPre + data[this.setting.id]; this.items[key] = data; const masterKey = this.itemPre + data[this.setting.masterId]; if (!this.masterIndex[masterKey]) { this.masterIndex[masterKey] = []; } this.masterIndex[masterKey].push(data); } for (const prop in this.masterIndex) { this.resortPart(this.masterIndex[prop]); } } _addDatas(data, resort) { const datas = data instanceof Array ? data : [data]; for (const d of datas) { const key = this.itemPre + d[this.setting.id]; this.items[key] = d; const masterKey = this.itemPre + d[this.setting.masterId]; if (!this.masterIndex[masterKey]) this.masterIndex[masterKey] = []; this.masterIndex[masterKey].push(d); if (resort.indexOf(masterKey) < 0) resort.push(masterKey); } } /** * 更新数据 * @param datas */ _updateDatas(data, resort) { const datas = data instanceof Array ? data : [data]; for (const d of datas) { const item = this.getItem(d[this.setting.id]); if (!item) continue; for (const prop in d) { item[prop] = d[prop]; } const masterKey = this.itemPre + item[this.setting.masterId]; if (resort.indexOf(masterKey) < 0) resort.push(masterKey); } } /** * 移除数据 * @param datas */ _removeDatas(data, resort) { if (!data) { return; } const datas = data instanceof Array ? data : [data]; for (let i = datas.length - 1; i >= 0; i--) { const id = datas[i]; const d = this.getItem(id); this.datas.splice(this.datas.indexOf(d), 1); const key = this.itemPre + d[this.setting.id]; delete this.items[key]; const range = this.getPartData(d[this.setting.masterId]); range.splice(range.indexOf(d), 1); } } updateDatas(data) { const resort = []; if (data.add) this._addDatas(data.add, resort); if (data.del) this._removeDatas(data.del, resort); if (data.update) this._updateDatas(data.update, resort); for (const s of resort) { this.resortPart(this.masterIndex[s]); this.filterPart(this.masterIndex[s]); } } /** * 移除数据 - 根据分类id * @param mid */ removeDatasByMasterId(mid) { const masterKey = this.itemPre + mid; const range = this.masterIndex[masterKey]; if (range) { delete this.masterIndex[masterKey]; for (const r of range) { this.datas.splice(this.datas.indexOf(r), 1); const key = this.itemPre + r[this.setting.id]; delete this.items[key]; } } } getItem(id) { return this.items[this.itemPre + id]; } getPartData(mid) { return this.masterIndex[this.itemPre + mid]; } set sort(sort) { this.setting.sort = sort; for (const key in this.masterIndex) { this.resortPart(this.masterIndex[key]); } } set filter(condition) { this._filter = condition; for (const key in this.masterIndex) { this.filterPart(this.masterIndex[key]); } } } return new AncillaryGcl(setting); }; const treeCalc = { mapTreeNode: function (tree) { const setting = tree.setting; let map = {}, maxLevel = 0; for (const node of tree.nodes) { let levelArr = map[node[setting.level]]; if (!levelArr) { levelArr = []; map[node[setting.level]] = levelArr; } if (node[setting.level] > maxLevel) { maxLevel = node[setting.level]; } levelArr.push(node); } return [maxLevel, map]; }, getMaxLevel: function (tree) { const setting = tree.setting; return Math.max.apply(Math, tree.datas.map(function (o) { return o[setting.level] })); }, calculateNode: function (tree, node) { if (node.children && node.children.length > 0) { const gather = node.children.reduce(function (rst, x) { const result = {}; for (const cf of tree.setting.calcFields) { result[cf] = ZhCalc.add(rst[cf], x[cf]); } return result; }); // 汇总子项 for (const cf of tree.setting.calcFields) { if (gather[cf]) { node[cf] = gather[cf]; } else { node[cf] = null; } } } // 自身运算 if (tree.setting.calcFun) { tree.setting.calcFun(node); } }, calculateLevelNode: function (tree, level) { const setting = tree.setting; const nodes = tree.datas.filter((n) => { return n[setting.level] === level }); for (const node of nodes) { this.calculateNode(tree, node); } }, calculateAll: function (tree) { const [maxLevel, levelMap] = this.mapTreeNode(tree); for (let i = maxLevel; i >= 0; i--) { const levelNodes = levelMap[i]; if (levelNodes && levelNodes.length > 0) { for (const node of levelNodes) { this.calculateNode(tree, node); } } } }, calculateParent: function (tree, node, converse = -1) { const setting = tree.setting; const nodes = tree.getFullPathNodes(node[setting.fullPath]); converse === -1 ? tree.sortByLevel(nodes) : tree.sortByLevelConverse(nodes); for (const n of nodes) { this.calculateNode(tree, n); } return nodes; } };