You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
5.4 KiB

import {deepClone} from "@/util/index"
import {createWorker} from '@/util/worker'
7 years ago
const DEFAULT_PROPS = {id: 'id', pid: 'pid', children: 'children', leafHasChildren: true}
7 years ago
/**
* 列表转树形结构
* @param {Array} list
* @param {Number|String|Function} rootSign 根节点的判定方法
* @param {Object} props 树的配置项
7 years ago
* @returns {Array}
*/
export function createTree(list, rootSign = 0, props = {}) {
7 years ago
if (!list || list.length <= 0) return []
const {
id = DEFAULT_PROPS.id,
pid = DEFAULT_PROPS.pid,
children = DEFAULT_PROPS.children,
leafHasChildren = DEFAULT_PROPS.leafHasChildren
} = props
const info = {}
7 years ago
list.forEach(i => {
info[i[id]] = i
if (leafHasChildren) i[children] = []
7 years ago
})
7 years ago
return list.filter(node => {
const key = node[pid]
const parent = info[key]
if (parent) {
if (!parent[children]) parent[children] = []
parent[children].push(node)
}
return typeof rootSign === 'function' ? rootSign(node) : key === rootSign
7 years ago
})
}
/**
* 完全树full拿到某些带value的节点数组limit获得裁剪后的树
* 只用于裁剪客户和供应商的行政区域树
* @param full
* @param limit
*/
export function createLimitTree(full, limit) {
const map = limit.reduce((m, n) => {
m[n.id] = n.value
return m
}, {})
full = deepClone(full)
7 years ago
const result = shakeTree(full, node => {
7 years ago
const value = map[node.id]
if (value !== undefined) {
node.value = value
return true
}
return false
})
result.forEach(i => calc(i))
return result
}
/**
* createLimitTree的另一版本
* @param fullMap 完全树的节点map
* @param limit
*/
export function createLimitTreeByMap(fullMap, limit) {
const resultNodes = {}
//从该节点往上查找父节点
function findParent(node) {
//如果该节点已存在于结果集中,说明包含该节点的上级分支也全部存在,所以跳过
if (resultNodes[node.id]) return
//使用full中的数据,仅保留node的value
const fullNode = fullMap[node.id]
if (!fullNode) return
resultNodes[fullNode.id] = {...node, ...fullNode}
//查找父节点
const parent = fullMap[fullNode.pid]
if (!parent) return
return findParent(parent)
}
for (const node of limit) {
if (!fullMap[node.id]) continue
findParent(node)
}
const result = createTree(Object.values(resultNodes), '0')
result.forEach(i => calc(i))
return result
}
/**
* 根据判断函数裁剪树当节点不满足predicate且无下级节点时将被裁剪
* @param tree
* @param predicate
* @param childrenKey
* @returns {*[]} 经过裁剪后的树
*/
export function shakeTree(tree = [], predicate = () => true, childrenKey = 'children') {
7 years ago
return tree.filter(data => {
data[childrenKey] = shakeTree(data[childrenKey], predicate)
7 years ago
return predicate(data) || data[childrenKey].length
})
}
export function calc(node, valueKey = 'value', childrenKey = 'children') {
if (!node) return 0
7 years ago
const children = node[childrenKey]
const childValue = node[valueKey] || 0
7 years ago
if (!children) return childValue
7 years ago
const value = childValue + children.reduce((v, child) => v + calc(child), 0)
7 years ago
node[valueKey] = value
7 years ago
return value
}
export function getNodeId(arr) {
if (!arr) return []
const res = []
7 years ago
arr.forEach(i => {
res.push(i.id)
if (i.children && i.children.length > 0) {
res.push(...getNodeId(i.children))
}
})
7 years ago
return res
}
//树转一维数组
export function flatTree(tree, childrenKey = 'children') {
const result = []
tree.forEach(node => {
if (node[childrenKey]) {
result.push(node)
result.push.apply(result, flatTree(node[childrenKey], childrenKey))
}
else result.push(node)
})
return result
}
7 years ago
export function getNodesByDfs(node) {
const nodes = []
const stack = []
7 years ago
stack.push(node)
7 years ago
while (stack.length > 0) {
const item = stack.pop()
7 years ago
nodes.push(item)
const children = item.children
7 years ago
for (let i = children.length - 1; i >= 0; i--) {
stack.push(children[i])
}
}
7 years ago
return nodes
}
export function getNodesByBfs(node) {
const nodes = []
const queue = []
7 years ago
queue.unshift(node)
7 years ago
while (queue.length > 0) {
const item = queue.shift()
7 years ago
nodes.push(item)
queue.push(...item.children)
}
7 years ago
return nodes
}
//借助worker生成树
export function createTreeByWorker(list) {
return new Promise(resolve => {
const worker = createWorker(workerTree, list, ({data}) => {
7 years ago
resolve(data)
worker.terminate()
})
})
}
function workerTree() {
function createTree(list, rootSign = 0, idKey = 'id', pidKey = 'pid', childrenKey = 'children') {
if (!list || list.length <= 0) return []
let info = {}
list.forEach(i => {
i[childrenKey] = []
info[i[idKey]] = i
})
return list.filter(node => {
const key = node[pidKey]
info[key] && info[key][childrenKey].push(node)
return key === rootSign
7 years ago
})
}
self.addEventListener('message', ({data}) => {
self.postMessage(createTree(data))
})
}