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.
223 lines
5.5 KiB
223 lines
5.5 KiB
import {createWorker} from '@/utils/worker'
|
|
|
|
/**
|
|
* 列表转树形结构
|
|
* @param {Array} list
|
|
* @param {Number|String} rootSign 根节点的pid值
|
|
* @param {String} idKey
|
|
* @param {String} pidKey
|
|
* @param {String} childrenKey
|
|
* @returns {Array}
|
|
*/
|
|
export function createTree(list, rootSign = 0, idKey = 'id', pidKey = 'pid', childrenKey = 'children') {
|
|
if (!list || list.length <= 0) return []
|
|
|
|
const info = {}
|
|
|
|
list.forEach(i => {
|
|
i[childrenKey] = []
|
|
info[i[idKey]] = i
|
|
})
|
|
|
|
return list.filter(node => {
|
|
info[node[pidKey]] && info[node[pidKey]][childrenKey].push(node)
|
|
return node[pidKey] === rootSign
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 完全树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 = JSON.parse(JSON.stringify(full))
|
|
|
|
const result = shakeTree(full, node => {
|
|
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') {
|
|
return tree.filter(data => {
|
|
data[childrenKey] = shakeTree(data[childrenKey], predicate)
|
|
return predicate(data) || data[childrenKey].length
|
|
})
|
|
}
|
|
|
|
export function calc(node, valueKey = 'value', childrenKey = 'children') {
|
|
if (!node) return 0
|
|
|
|
const children = node[childrenKey]
|
|
const childValue = node[valueKey] || 0
|
|
|
|
if (!children) return childValue
|
|
|
|
const value = childValue + children.reduce((v, child) => v + calc(child), 0)
|
|
|
|
node[valueKey] = value
|
|
|
|
return value
|
|
}
|
|
|
|
/**
|
|
* el-tree展开收缩
|
|
* 有兴趣的可以研究下怎么平滑展开收缩
|
|
* @param ref el-tree实例
|
|
* @param action expand | collapse
|
|
* @param level 展开的节点最大深度,为0时匹配全部节点
|
|
*/
|
|
export function elTreeControl(ref, action = 'expand', level = 1) {
|
|
ref.store._getAllNodes().forEach(node => {
|
|
const value = action === 'expand'
|
|
node.expanded = level === 0 || node.level <= level ? value : !value
|
|
})
|
|
}
|
|
|
|
export function getNodeId(arr) {
|
|
if (!arr) return []
|
|
|
|
const res = []
|
|
|
|
arr.forEach(i => {
|
|
res.push(i.id)
|
|
if (i.children && i.children.length > 0) {
|
|
res.push(...getNodeId(i.children))
|
|
}
|
|
})
|
|
|
|
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
|
|
}
|
|
|
|
export function getNodesByDfs(node) {
|
|
const nodes = []
|
|
const stack = []
|
|
|
|
stack.push(node)
|
|
|
|
while (stack.length > 0) {
|
|
const item = stack.pop()
|
|
nodes.push(item)
|
|
const children = item.children
|
|
for (let i = children.length - 1; i >= 0; i--) {
|
|
stack.push(children[i])
|
|
}
|
|
}
|
|
|
|
return nodes
|
|
}
|
|
|
|
export function getNodesByBfs(node) {
|
|
const nodes = []
|
|
const queue = []
|
|
queue.unshift(node)
|
|
|
|
while (queue.length > 0) {
|
|
const item = queue.shift()
|
|
nodes.push(item)
|
|
queue.push(...item.children)
|
|
}
|
|
|
|
return nodes
|
|
}
|
|
|
|
//借助worker生成树
|
|
export function createTreeByWorker(list) {
|
|
return new Promise(resolve => {
|
|
const worker = createWorker(workerTree, list, ({data}) => {
|
|
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 => {
|
|
info[node[pidKey]] && info[node[pidKey]][childrenKey].push(node)
|
|
return node[pidKey] === rootSign
|
|
})
|
|
}
|
|
|
|
self.addEventListener('message', ({data}) => {
|
|
self.postMessage(createTree(data))
|
|
})
|
|
}
|
|
|