From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/utils/tree.ts | 403 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 403 insertions(+), 0 deletions(-)
diff --git a/src/utils/tree.ts b/src/utils/tree.ts
new file mode 100644
index 0000000..e5db503
--- /dev/null
+++ b/src/utils/tree.ts
@@ -0,0 +1,403 @@
+interface TreeHelperConfig {
+ id: string
+ children: string
+ pid: string
+}
+
+const DEFAULT_CONFIG: TreeHelperConfig = {
+ id: 'id',
+ children: 'children',
+ pid: 'pid'
+}
+export const defaultProps = {
+ children: 'children',
+ label: 'name',
+ value: 'id',
+ isLeaf: 'leaf',
+ emitPath: false // 鐢ㄤ簬 cascader 缁勪欢锛氬湪閫変腑鑺傜偣鏀瑰彉鏃讹紝鏄惁杩斿洖鐢辫鑺傜偣鎵�鍦ㄧ殑鍚勭骇鑿滃崟鐨勫�兼墍缁勬垚鐨勬暟缁勶紝鑻ヨ缃� false锛屽垯鍙繑鍥炶鑺傜偣鐨勫��
+}
+
+const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config)
+
+// tree from list
+export const listToTree = <T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] => {
+ const conf = getConfig(config) as TreeHelperConfig
+ const nodeMap = new Map()
+ const result: T[] = []
+ const { id, children, pid } = conf
+
+ for (const node of list) {
+ node[children] = node[children] || []
+ nodeMap.set(node[id], node)
+ }
+ for (const node of list) {
+ const parent = nodeMap.get(node[pid])
+ ;(parent ? parent.children : result).push(node)
+ }
+ return result
+}
+
+export const treeToList = <T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T => {
+ config = getConfig(config)
+ const { children } = config
+ const result: any = [...tree]
+ for (let i = 0; i < result.length; i++) {
+ if (!result[i][children!]) continue
+ result.splice(i + 1, 0, ...result[i][children!])
+ }
+ return result
+}
+
+export const findNode = <T = any>(
+ tree: any,
+ func: Fn,
+ config: Partial<TreeHelperConfig> = {}
+): T | null => {
+ config = getConfig(config)
+ const { children } = config
+ const list = [...tree]
+ for (const node of list) {
+ if (func(node)) return node
+ node[children!] && list.push(...node[children!])
+ }
+ return null
+}
+
+export const findNodeAll = <T = any>(
+ tree: any,
+ func: Fn,
+ config: Partial<TreeHelperConfig> = {}
+): T[] => {
+ config = getConfig(config)
+ const { children } = config
+ const list = [...tree]
+ const result: T[] = []
+ for (const node of list) {
+ func(node) && result.push(node)
+ node[children!] && list.push(...node[children!])
+ }
+ return result
+}
+
+export const findPath = <T = any>(
+ tree: any,
+ func: Fn,
+ config: Partial<TreeHelperConfig> = {}
+): T | T[] | null => {
+ config = getConfig(config)
+ const path: T[] = []
+ const list = [...tree]
+ const visitedSet = new Set()
+ const { children } = config
+ while (list.length) {
+ const node = list[0]
+ if (visitedSet.has(node)) {
+ path.pop()
+ list.shift()
+ } else {
+ visitedSet.add(node)
+ node[children!] && list.unshift(...node[children!])
+ path.push(node)
+ if (func(node)) {
+ return path
+ }
+ }
+ }
+ return null
+}
+
+export const findPathAll = (tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) => {
+ config = getConfig(config)
+ const path: any[] = []
+ const list = [...tree]
+ const result: any[] = []
+ const visitedSet = new Set(),
+ { children } = config
+ while (list.length) {
+ const node = list[0]
+ if (visitedSet.has(node)) {
+ path.pop()
+ list.shift()
+ } else {
+ visitedSet.add(node)
+ node[children!] && list.unshift(...node[children!])
+ path.push(node)
+ func(node) && result.push([...path])
+ }
+ }
+ return result
+}
+
+export const filter = <T = any>(
+ tree: T[],
+ func: (n: T) => boolean,
+ config: Partial<TreeHelperConfig> = {}
+): T[] => {
+ config = getConfig(config)
+ const children = config.children as string
+
+ function listFilter(list: T[]) {
+ return list
+ .map((node: any) => ({ ...node }))
+ .filter((node) => {
+ node[children] = node[children] && listFilter(node[children])
+ return func(node) || (node[children] && node[children].length)
+ })
+ }
+
+ return listFilter(tree)
+}
+
+export const forEach = <T = any>(
+ tree: T[],
+ func: (n: T) => any,
+ config: Partial<TreeHelperConfig> = {}
+): void => {
+ config = getConfig(config)
+ const list: any[] = [...tree]
+ const { children } = config
+ for (let i = 0; i < list.length; i++) {
+ // func 杩斿洖true灏辩粓姝㈤亶鍘嗭紝閬垮厤澶ч噺鑺傜偣鍦烘櫙涓嬫棤鎰忎箟寰幆锛屽紩璧锋祻瑙堝櫒鍗¢】
+ if (func(list[i])) {
+ return
+ }
+ children && list[i][children] && list.splice(i + 1, 0, ...list[i][children])
+ }
+}
+
+/**
+ * @description: Extract tree specified structure
+ */
+export const treeMap = <T = any>(
+ treeData: T[],
+ opt: { children?: string; conversion: Fn }
+): T[] => {
+ return treeData.map((item) => treeMapEach(item, opt))
+}
+
+/**
+ * @description: Extract tree specified structure
+ */
+export const treeMapEach = (
+ data: any,
+ { children = 'children', conversion }: { children?: string; conversion: Fn }
+) => {
+ const haveChildren = Array.isArray(data[children]) && data[children].length > 0
+ const conversionData = conversion(data) || {}
+ if (haveChildren) {
+ return {
+ ...conversionData,
+ [children]: data[children].map((i: number) =>
+ treeMapEach(i, {
+ children,
+ conversion
+ })
+ )
+ }
+ } else {
+ return {
+ ...conversionData
+ }
+ }
+}
+
+/**
+ * 閫掑綊閬嶅巻鏍戠粨鏋�
+ * @param treeDatas 鏍�
+ * @param callBack 鍥炶皟
+ * @param parentNode 鐖惰妭鐐�
+ */
+export const eachTree = (treeDatas: any[], callBack: Fn, parentNode = {}) => {
+ treeDatas.forEach((element) => {
+ const newNode = callBack(element, parentNode) || element
+ if (element.children) {
+ eachTree(element.children, callBack, newNode)
+ }
+ })
+}
+
+/**
+ * 鏋勯�犳爲鍨嬬粨鏋勬暟鎹�
+ * @param {*} data 鏁版嵁婧�
+ * @param {*} id id瀛楁 榛樿 'id'
+ * @param {*} parentId 鐖惰妭鐐瑰瓧娈� 榛樿 'parentId'
+ * @param {*} children 瀛╁瓙鑺傜偣瀛楁 榛樿 'children'
+ */
+export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => {
+ if (!Array.isArray(data)) {
+ console.warn('data must be an array')
+ return []
+ }
+ const config = {
+ id: id || 'id',
+ parentId: parentId || 'parentId',
+ childrenList: children || 'children'
+ }
+
+ const childrenListMap = {}
+ const nodeIds = {}
+ const tree: any[] = []
+
+ for (const d of data) {
+ const parentId = d[config.parentId]
+ if (childrenListMap[parentId] == null) {
+ childrenListMap[parentId] = []
+ }
+ nodeIds[d[config.id]] = d
+ childrenListMap[parentId].push(d)
+ }
+
+ for (const d of data) {
+ const parentId = d[config.parentId]
+ if (nodeIds[parentId] == null) {
+ tree.push(d)
+ }
+ }
+
+ for (const t of tree) {
+ adaptToChildrenList(t)
+ }
+
+ function adaptToChildrenList(o) {
+ if (childrenListMap[o[config.id]] !== null) {
+ o[config.childrenList] = childrenListMap[o[config.id]]
+ }
+ if (o[config.childrenList]) {
+ for (const c of o[config.childrenList]) {
+ adaptToChildrenList(c)
+ }
+ }
+ }
+
+ return tree
+}
+
+/**
+ * 鏋勯�犳爲鍨嬬粨鏋勬暟鎹�
+ * @param {*} data 鏁版嵁婧�
+ * @param {*} id id瀛楁 榛樿 'id'
+ * @param {*} parentId 鐖惰妭鐐瑰瓧娈� 榛樿 'parentId'
+ * @param {*} children 瀛╁瓙鑺傜偣瀛楁 榛樿 'children'
+ * @param {*} rootId 鏍笽d 榛樿 0
+ */
+// @ts-ignore
+export const handleTree2 = (data, id, parentId, children, rootId) => {
+ id = id || 'id'
+ parentId = parentId || 'parentId'
+ // children = children || 'children'
+ rootId =
+ rootId ||
+ Math.min(
+ ...data.map((item) => {
+ return item[parentId]
+ })
+ ) ||
+ 0
+ // 瀵规簮鏁版嵁娣卞害鍏嬮殕
+ const cloneData = JSON.parse(JSON.stringify(data))
+ // 寰幆鎵�鏈夐」
+ const treeData = cloneData.filter((father) => {
+ const branchArr = cloneData.filter((child) => {
+ // 杩斿洖姣忎竴椤圭殑瀛愮骇鏁扮粍
+ return father[id] === child[parentId]
+ })
+ branchArr.length > 0 ? (father.children = branchArr) : ''
+ // 杩斿洖绗竴灞�
+ return father[parentId] === rootId
+ })
+ return treeData !== '' ? treeData : data
+}
+
+/**
+ * 鏍¢獙閫変腑鐨勮妭鐐癸紝鏄惁涓烘寚瀹� level
+ *
+ * @param tree 瑕佹搷浣滅殑鏍戠粨鏋勬暟鎹�
+ * @param nodeId 闇�瑕佸垽鏂湪浠�涔堝眰绾х殑鏁版嵁
+ * @param level 妫�鏌ョ殑绾у埆, 榛樿妫�鏌ュ埌浜岀骇
+ * @return true 鏄紱false 鍚�
+ */
+export const checkSelectedNode = (tree: any[], nodeId: any, level = 2): boolean => {
+ if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) {
+ console.warn('tree must be an array')
+ return false
+ }
+
+ // 鏍¢獙鏄惁鏄竴绾ц妭鐐�
+ if (tree.some((item) => item.id === nodeId)) {
+ return false
+ }
+
+ // 閫掑綊璁℃暟
+ let count = 1
+
+ // 娣卞眰娆℃牎楠�
+ function performAThoroughValidation(arr: any[]): boolean {
+ count += 1
+ for (const item of arr) {
+ if (item.id === nodeId) {
+ return true
+ } else if (typeof item.children !== 'undefined' && item.children.length !== 0) {
+ if (performAThoroughValidation(item.children)) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ for (const item of tree) {
+ count = 1
+ if (performAThoroughValidation(item.children)) {
+ // 鎵惧埌鍚庡姣旀槸鍚︽槸鏈熸湜鐨勫眰绾�
+ if (count >= level) {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+/**
+ * 鑾峰彇鑺傜偣鐨勫畬鏁寸粨鏋�
+ * @param tree 鏍戞暟鎹�
+ * @param nodeId 鑺傜偣 id
+ */
+export const treeToString = (tree: any[], nodeId) => {
+ if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) {
+ console.warn('tree must be an array')
+ return ''
+ }
+ // 鏍¢獙鏄惁鏄竴绾ц妭鐐�
+ const node = tree.find((item) => item.id === nodeId)
+ if (typeof node !== 'undefined') {
+ return node.name
+ }
+ let str = ''
+
+ function performAThoroughValidation(arr) {
+ if (typeof arr === 'undefined' || !Array.isArray(arr) || arr.length === 0) {
+ return false
+ }
+ for (const item of arr) {
+ if (item.id === nodeId) {
+ str += ` / ${item.name}`
+ return true
+ } else if (typeof item.children !== 'undefined' && item.children.length !== 0) {
+ str += ` / ${item.name}`
+ if (performAThoroughValidation(item.children)) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ for (const item of tree) {
+ str = `${item.name}`
+ if (performAThoroughValidation(item.children)) {
+ break
+ }
+ }
+ return str
+}
--
Gitblit v1.8.0