20260901173242

This commit is contained in:
oneao committed 2026-09-01 17:32:43 +08:00
1 parent 3bbcafc5be
commit 53aba8b956
21 files changed
+1595 -704

No files matched your search

+135
View File
@@ -53,3 +53,138 @@ export function sortTree(tree, xhKey = 'b_xh', idKey = 'b_id') {
}
return tree
}
/**
* 在树中递归查找指定 id 的节点。
* @param {Array} nodes 树形数组
* @param {string|number} id 目标节点 ID
* @param {string} idKey 节点 ID 字段名,默认 "b_id"
* @param {string} childrenKey 子节点字段名,默认 "children"
*/
export function findTreeNode(nodes, id, idKey = 'b_id', childrenKey = 'children') {
for (const node of nodes) {
if (String(node[idKey]) === String(id)) return node
if (node[childrenKey]) {
const found = findTreeNode(node[childrenKey], id, idKey, childrenKey)
if (found) return found
}
}
return null
}
/**
* 递归收集所有节点 key。
* @param {Array} nodes 树形数组
* @param {string} idKey 节点 ID 字段名,默认 "b_id"
* @param {string} childrenKey 子节点字段名,默认 "children"
*/
export function collectAllKeys(nodes, idKey = 'b_id', childrenKey = 'children') {
const keys = []
const walk = (list) => {
for (const node of list) {
keys.push(String(node[idKey]))
if (node[childrenKey]) walk(node[childrenKey])
}
}
walk(nodes)
return keys
}
/**
* 从根到目标节点的祖先路径(不包含目标节点自身)。
* @param {Array} nodes 树形数组
* @param {string|number} targetId 目标节点 ID
* @param {string} idKey 节点 ID 字段名,默认 "b_id"
* @param {string} childrenKey 子节点字段名,默认 "children"
*/
export function expandAncestors(nodes, targetId, idKey = 'b_id', childrenKey = 'children') {
const keys = []
const walk = (list, ancestors) => {
for (const node of list) {
const key = String(node[idKey])
if (key === String(targetId)) {
keys.push(...ancestors)
return true
}
if (node[childrenKey] && walk(node[childrenKey], [...ancestors, key])) return true
}
return false
}
walk(nodes, [])
return keys
}
/**
* 按关键字匹配树节点名称/编码,命中节点保留其子树。
* @param {Array} nodes 树形数组
* @param {string} keyword 搜索关键字
* @param {string[]} textKeys 搜索匹配的字段名列表,默认 ["b_name", "b_code"]
* @param {string} childrenKey 子节点字段名,默认 "children"
*/
export function filterTreeByText(
nodes,
keyword,
textKeys = ['b_name', 'b_code'],
childrenKey = 'children',
) {
const kw = String(keyword || '').trim().toLowerCase()
if (!kw) return nodes
const result = []
for (const node of nodes) {
const hit = textKeys.some((k) => String(node[k] || '').toLowerCase().includes(kw))
const children = node[childrenKey] ? filterTreeByText(node[childrenKey], keyword, textKeys, childrenKey) : undefined
if (hit || children?.length) {
result.push({ ...node, [childrenKey]: children })
}
}
return result
}
/**
* 将节点插入到树中(按 parentIdKey 匹配父节点,顶级节点 parentIdKey 为 null/undefined 时插入根层)。
* 就地修改树,不返回新数组。
* @param {Array} nodes 树形数组(就地修改)
* @param {Object} node 待插入节点
* @param {Object} [options]
* @param {string} [options.parentIdKey="b_parent_id"] 父节点 ID 字段名
* @param {string} [options.idKey="b_id"] 节点 ID 字段名
* @param {string} [options.childrenKey="children"] 子节点字段名
* @param {Function} [options.sort] 可选排序函数,插入所在层后调用(如 sortTree)
*/
export function insertTreeNode(
nodes,
node,
{ parentIdKey = 'b_parent_id', idKey = 'b_id', childrenKey = 'children', sort } = {},
) {
if (node[parentIdKey] == null) {
nodes.push(node)
if (sort) sort(nodes)
return
}
for (const n of nodes) {
if (String(n[idKey]) === String(node[parentIdKey])) {
n[childrenKey] = n[childrenKey] || []
n[childrenKey].push(node)
if (sort) sort(n[childrenKey])
return
}
if (n[childrenKey]) insertTreeNode(n[childrenKey], node, { parentIdKey, idKey, childrenKey, sort })
}
}
/**
* 从树中移除指定 id 的节点(就地修改)。
* @param {Array} nodes 树形数组(就地修改)
* @param {string|number} id 目标节点 ID
* @param {string} idKey 节点 ID 字段名,默认 "b_id"
* @param {string} childrenKey 子节点字段名,默认 "children"
*/
export function removeTreeNode(nodes, id, idKey = 'b_id', childrenKey = 'children') {
for (let i = 0; i < nodes.length; i++) {
if (String(nodes[i][idKey]) === String(id)) {
nodes.splice(i, 1)
return
}
if (nodes[i][childrenKey]) removeTreeNode(nodes[i][childrenKey], id, idKey, childrenKey)
}
}