import { isArray, isObject } from 'ut2';
/**
* 递归处理空子级
*
* @private
* @param {Object[]} arr 列表数据
* @param {Object} [options] 配置项
* @param {string} [options.childrenField='children'] 子级字段名称
* @param {'none'|'null'} [options.emptyChildrenValue='none'] 子级为空时的值,none表示删除该子级,null表示为null,array表示为[]。
*/
function processEmptyChildren(arr, options) {
const { childrenField = 'children', emptyChildrenValue = 'none' } = options;
arr.forEach((item) => {
if (item[childrenField].length <= 0) {
if (emptyChildrenValue === 'null') {
// @ts-ignore
item[childrenField] = null;
}
else {
delete item[childrenField];
}
}
else {
processEmptyChildren(item[childrenField], options);
}
});
}
/**
* 列表数据转树结构
*
* @static
* @alias module:Tree.listToTree
* @since 4.14.0
* @param {Object[]} list 列表数据
* @param {Object} [options] 配置项
* @param {string} [options.keyField='id'] 当前数据的键值字段名称
* @param {string} [options.parentField='pid'] 当前数据的父级字段名称
* @param {string} [options.childrenField='children'] 子级字段名称
* @param {'none'|'null'|'array'} [options.emptyChildrenValue='none'] 子级为空时的值,none表示删除该子级,null表示为null,array表示为[]。
* @param {'spread'|'self'} [options.nodeAssign='spread'] 节点赋值方式。spread表示使用展开运算符创建新值,self表示使用自身对象。
* @returns {Object[]} 树结构
* @example
*
* const menus = [
* { id: '1', name: '首页', code: 'trade', pid: null },
* { id: '2', name: '交易管理', code: 'trade', pid: null },
* { id: '3', name: '交易查询', code: 'trade-1', pid: '2' },
* { id: '4', name: '交易查询-查询操作', code: 'trade-1-1', pid: '3' },
* { id: '5', name: '权限管理', code: 'authorization', pid: null },
* { id: '6', name: '角色管理', code: 'authorization-1', pid: '5' },
* { id: '7', name: '用户管理', code: 'authorization-2', pid: '5' }
* ];
* listToTree(menus);
* // [{id:'1',name:'首页',code:'trade',pid:null},{id:'2',name:'交易管理',code:'trade',pid:null,children:[{id:'3',name:'交易查询',code:'trade-1',pid:'2',children:[{id:'4',name:'交易查询-查询操作',code:'trade-1-1',pid:'3'}]}]},{id:'5',name:'权限管理',code:'authorization',pid:null,children:[{id:'6',name:'角色管理',code:'authorization-1',pid:'5'},{id:'7',name:'用户管理',code:'authorization-2',pid:'5'}]}]
*
* // 自定义子级字段名
* listToTree(basicMenus, { childrenField: 'childs' });
* // [{id:'1',name:'首页',code:'trade',pid:null},{id:'2',name:'交易管理',code:'trade',pid:null,childs:[{id:'3',name:'交易查询',code:'trade-1',pid:'2',childs:[{id:'4',name:'交易查询-查询操作',code:'trade-1-1',pid:'3'}]}]},{id:'5',name:'权限管理',code:'authorization',pid:null,childs:[{id:'6',name:'角色管理',code:'authorization-1',pid:'5'},{id:'7',name:'用户管理',code:'authorization-2',pid:'5'}]}]
*
*/
function listToTree(list, options = {}) {
const { keyField = 'id', parentField = 'pid', childrenField = 'children', emptyChildrenValue = 'none', nodeAssign = 'spread' } = options;
const tree = [];
const record = {};
if (!isArray(list)) {
return tree;
}
list.forEach((item) => {
if (isObject(item)) {
const newItem = nodeAssign === 'spread' ? { ...item } : item;
const id = newItem[keyField];
const pid = newItem[parentField];
if (record[id]) {
// @ts-ignore
newItem[childrenField] = record[id];
}
else {
// @ts-ignore
newItem[childrenField] = record[id] = [];
}
if (pid) {
if (!record[pid]) {
record[pid] = [newItem];
}
else {
record[pid].push(newItem);
}
}
else {
// @ts-ignore
tree.push(newItem);
}
}
});
if (emptyChildrenValue !== 'array') {
// @ts-ignore
processEmptyChildren(tree, options);
}
return tree;
}
export default listToTree;