a2bei4-utils 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tree.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tree.js","sources":["../src/source/tree.js"],"sourcesContent":["/**\r\n * 把嵌套树拍平成 `{ [id]: node }` 映射,同时把原 `children` 置为 `null`。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} data - 嵌套树森林\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {Record<string, T & { [k in typeof childrenKey]: null }>} id→节点的映射表\r\n */\r\nexport function nestedTree2IdMap(data, idKey = \"id\", childrenKey = \"children\") {\r\n const retObj = {};\r\n function fn(nodes) {\r\n if (Array.isArray(nodes) && nodes.length > 0) {\r\n nodes.forEach((node) => {\r\n retObj[node[idKey]] = { ...node };\r\n retObj[node[idKey]][childrenKey] = null;\r\n\r\n fn(node[childrenKey]);\r\n });\r\n }\r\n }\r\n fn(data);\r\n return retObj;\r\n}\r\n\r\n/**\r\n * 把**已包含完整父子关系**的扁平节点列表还原成嵌套树(森林)。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} nodes - 扁平节点列表(必须包含 id / parentId)\r\n * @param {number | string} [parentId=0] - 根节点标识值\r\n * @param {Object} [opts] - 字段映射配置\r\n * @param {string} [opts.idKey='id'] - 节点主键\r\n * @param {string} [opts.parentKey='parentId'] - 父节点外键\r\n * @param {string} [opts.childrenKey='children'] - 存放子节点的字段\r\n * @returns {(T & { [k in typeof childrenKey]: T[] })[]} 嵌套树森林\r\n */\r\nexport function flatCompleteTree2NestedTree(nodes, parentId = 0, { idKey = \"id\", parentKey = \"parentId\", childrenKey = \"children\" } = {}) {\r\n const map = new Map(); // id -> node\r\n const items = []; // 多根森林\r\n\r\n // 1. 初始化:保证每个节点都有 children,并存入 map\r\n for (const item of nodes) {\r\n const node = { ...item, [childrenKey]: [] };\r\n map.set(item[idKey], node);\r\n }\r\n\r\n // 2. 建立父子关系\r\n for (const item of nodes) {\r\n const node = map.get(item[idKey]);\r\n const parentIdVal = item[parentKey];\r\n\r\n if (parentIdVal === parentId) {\r\n // 根层\r\n items.push(node);\r\n } else {\r\n // 非根层:找到父节点,把自己挂上去\r\n const parent = map.get(parentIdVal);\r\n if (parent) parent[childrenKey].push(node);\r\n // 如果 parent 不存在,说明数据不完整,可自定义处理\r\n }\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {string | number} id - 要查找的 id\r\n * @param {T[]} arr - 嵌套树森林\r\n * @param {string} [resultKey='name'] - 需要返回的字段\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {any} 找到的值;未找到返回 `undefined`\r\n */\r\nexport const findObjAttrValueById = function findObjAttrValueByIdFn(id, arr, resultKey = \"name\", idKey = \"id\", childrenKey = \"children\") {\r\n if (Array.isArray(arr) && arr.length > 0) {\r\n for (let i = 0; i < arr.length; i++) {\r\n const item = arr[i];\r\n if (item[idKey]?.toString() === id?.toString()) {\r\n return item[resultKey];\r\n } else if (Array.isArray(item[childrenKey]) && item[childrenKey].length > 0) {\r\n const result = findObjAttrValueByIdFn(id, item[childrenKey], resultKey, idKey, childrenKey);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * 从服务端返回的已选 id 数组里,提取出\r\n * 1. 叶子节点\r\n * 2. 所有子节点都被选中的父节点\r\n * 其余父节点一律丢弃(由前端 Tree 自动算半选)\r\n *\r\n * @param {Array} treeData 完整树\r\n * @param {Array} selectedKeys 后端给的选中 id 数组\r\n * @param {String} idKey 节点唯一字段\r\n * @param {String} childrenKey 子节点字段\r\n * @returns {{checked: string[], halfChecked: string[]}}\r\n */\r\nexport function extractFullyCheckedKeys(treeData, selectedKeys, idKey = \"id\", childrenKey = \"children\") {\r\n const selectedSet = new Set(selectedKeys);\r\n const checked = new Set();\r\n const halfChecked = new Set();\r\n\r\n /* 返回值含义\r\n 0 - 未选中\r\n 1 - 半选\r\n 2 - 全选\r\n */\r\n function dfs(node) {\r\n const nodeId = node[idKey];\r\n const children = node[childrenKey] || [];\r\n\r\n // 叶子\r\n if (!children.length) {\r\n if (selectedSet.has(nodeId)) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n return 0;\r\n }\r\n\r\n // 非叶子\r\n let allChecked = true;\r\n let someChecked = false;\r\n\r\n children.forEach((child) => {\r\n const childState = dfs(child);\r\n if (childState !== 2) allChecked = false;\r\n if (childState >= 1) someChecked = true;\r\n });\r\n\r\n // 当前节点本身在 selectedKeys 里,但子节点未全选 → 只能算半选\r\n if (selectedSet.has(nodeId)) {\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n\r\n // 当前节点不在 selectedKeys 里,看子节点\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n if (someChecked) {\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n return 0;\r\n }\r\n\r\n treeData.forEach(dfs);\r\n return {\r\n checked: [...checked],\r\n halfChecked: [...halfChecked]\r\n };\r\n}\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tree.js","sources":["../src/source/tree.js"],"sourcesContent":["/**\r\n * 把嵌套树拍平成 `{ [id]: node }` 映射,同时把原 `children` 置为 `null`。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} data - 嵌套树森林\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {Record<string, T & { [k in typeof childrenKey]: null }>} id→节点的映射表\r\n */\r\nexport function nestedTree2IdMap(data, idKey = \"id\", childrenKey = \"children\") {\r\n const retObj = {};\r\n function fn(nodes) {\r\n if (Array.isArray(nodes) && nodes.length > 0) {\r\n nodes.forEach((node) => {\r\n retObj[node[idKey]] = { ...node };\r\n retObj[node[idKey]][childrenKey] = null;\r\n\r\n fn(node[childrenKey]);\r\n });\r\n }\r\n }\r\n fn(data);\r\n return retObj;\r\n}\r\n\r\n/**\r\n * 把**已包含完整父子关系**的扁平节点列表还原成嵌套树(森林)。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {T[]} nodes - 扁平节点列表(必须包含 id / parentId)\r\n * @param {number | string} [parentId=0] - 根节点标识值\r\n * @param {Object} [opts] - 字段映射配置\r\n * @param {string} [opts.idKey='id'] - 节点主键\r\n * @param {string} [opts.parentKey='parentId'] - 父节点外键\r\n * @param {string} [opts.childrenKey='children'] - 存放子节点的字段\r\n * @returns {(T & { [k in typeof childrenKey]: T[] })[]} 嵌套树森林\r\n */\r\nexport function flatCompleteTree2NestedTree(nodes, parentId = 0, { idKey = \"id\", parentKey = \"parentId\", childrenKey = \"children\" } = {}) {\r\n const map = new Map(); // id -> node\r\n const items = []; // 多根森林\r\n\r\n // 1. 初始化:保证每个节点都有 children,并存入 map\r\n for (const item of nodes) {\r\n const node = { ...item, [childrenKey]: [] };\r\n map.set(item[idKey], node);\r\n }\r\n\r\n // 2. 建立父子关系\r\n for (const item of nodes) {\r\n const node = map.get(item[idKey]);\r\n const parentIdVal = item[parentKey];\r\n\r\n if (parentIdVal === parentId) {\r\n // 根层\r\n items.push(node);\r\n } else {\r\n // 非根层:找到父节点,把自己挂上去\r\n const parent = map.get(parentIdVal);\r\n if (parent) parent[childrenKey].push(node);\r\n // 如果 parent 不存在,说明数据不完整,可自定义处理\r\n }\r\n }\r\n\r\n return items;\r\n}\r\n\r\n/**\r\n * 在嵌套树中按 `id` 递归查找节点\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {string | number} id - 要查找的 id\r\n * @param {T[]} arr - 嵌套树森林\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {any} 找到的节点;未找到返回 `undefined`\r\n */\r\nexport const findTreeNodeById = function findTreeNodeByIdFn(id, arr, idKey = \"id\", childrenKey = \"children\") {\r\n if (Array.isArray(arr) && arr.length > 0) {\r\n for (let i = 0; i < arr.length; i++) {\r\n const item = arr[i];\r\n if (item[idKey]?.toString() === id?.toString()) {\r\n return item;\r\n } else if (Array.isArray(item[childrenKey]) && item[childrenKey].length > 0) {\r\n const result = findTreeNodeByIdFn(id, item[childrenKey], idKey, childrenKey);\r\n if (result) {\r\n return result;\r\n }\r\n }\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。\r\n *\r\n * @template T extends Record<PropertyKey, any>\r\n * @param {string | number} id - 要查找的 id\r\n * @param {T[]} arr - 嵌套树森林\r\n * @param {string} [resultKey='name'] - 需要返回的字段\r\n * @param {string} [idKey='id'] - 主键字段\r\n * @param {string} [childrenKey='children'] - 子节点字段\r\n * @returns {any} 找到的值;未找到返回 `undefined`\r\n */\r\nexport function findObjAttrValueById(id, arr, resultKey = \"name\", idKey = \"id\", childrenKey = \"children\") {\r\n return findTreeNodeById(id, arr, idKey, childrenKey)?.[resultKey];\r\n}\r\n\r\n/**\r\n * 从服务端返回的已选 id 数组里,提取出\r\n * 1. 叶子节点\r\n * 2. 所有子节点都被选中的父节点\r\n * 其余父节点一律丢弃(由前端 Tree 自动算半选)\r\n *\r\n * @param {Array} treeData 完整树\r\n * @param {Array} selectedKeys 后端给的选中 id 数组\r\n * @param {String} idKey 节点唯一字段\r\n * @param {String} childrenKey 子节点字段\r\n * @returns {{checked: string[], halfChecked: string[]}}\r\n */\r\nexport function extractFullyCheckedKeys(treeData, selectedKeys, idKey = \"id\", childrenKey = \"children\") {\r\n const selectedSet = new Set(selectedKeys);\r\n const checked = new Set();\r\n const halfChecked = new Set();\r\n\r\n /* 返回值含义\r\n 0 - 未选中\r\n 1 - 半选\r\n 2 - 全选\r\n */\r\n function dfs(node) {\r\n const nodeId = node[idKey];\r\n const children = node[childrenKey] || [];\r\n\r\n // 叶子\r\n if (!children.length) {\r\n if (selectedSet.has(nodeId)) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n return 0;\r\n }\r\n\r\n // 非叶子\r\n let allChecked = true;\r\n let someChecked = false;\r\n\r\n children.forEach((child) => {\r\n const childState = dfs(child);\r\n if (childState !== 2) allChecked = false;\r\n if (childState >= 1) someChecked = true;\r\n });\r\n\r\n // 当前节点本身在 selectedKeys 里,但子节点未全选 → 只能算半选\r\n if (selectedSet.has(nodeId)) {\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n\r\n // 当前节点不在 selectedKeys 里,看子节点\r\n if (allChecked) {\r\n checked.add(nodeId);\r\n return 2;\r\n }\r\n if (someChecked) {\r\n halfChecked.add(nodeId);\r\n return 1;\r\n }\r\n return 0;\r\n }\r\n\r\n treeData.forEach(dfs);\r\n return {\r\n checked: [...checked],\r\n halfChecked: [...halfChecked]\r\n };\r\n}\r\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "a2bei4-utils",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "🧰 零依赖、ESM 的 JS 业务工具箱:数组乱序/深浅克隆、防抖节流、URL/query 解析、Date/时长格式化、随机汉字/字母、文件下载、事件总线、UUID/分布式短 ID、树结构互转等 40+ 常用函数 & 类,Tree-Shaking 友好。",
5
5
  "private": false,
6
6
  "type": "module",
@@ -55,6 +55,11 @@
55
55
  "import": "./dist/id.js",
56
56
  "require": "./dist/id.cjs"
57
57
  },
58
+ "./menu": {
59
+ "types": "./types/menu.d.ts",
60
+ "import": "./dist/menu.js",
61
+ "require": "./dist/menu.cjs"
62
+ },
58
63
  "./timer": {
59
64
  "types": "./types/timer.d.ts",
60
65
  "import": "./dist/timer.js",
@@ -135,12 +140,12 @@
135
140
  },
136
141
  "homepage": "https://github.com/xiaodu114/a2bei4-utils",
137
142
  "devDependencies": {
138
- "@rollup/plugin-commonjs": "^28.0.6",
139
- "@rollup/plugin-node-resolve": "^16.0.2",
140
- "@rollup/plugin-terser": "^0.4.4",
141
- "prettier": "^3.6.2",
142
- "rollup": "^4.52.4",
143
- "rollup-plugin-dts": "^6.2.3",
143
+ "@rollup/plugin-commonjs": "^29.0.2",
144
+ "@rollup/plugin-node-resolve": "^16.0.3",
145
+ "@rollup/plugin-terser": "^1.0.0",
146
+ "prettier": "^3.8.1",
147
+ "rollup": "^4.60.0",
148
+ "rollup-plugin-dts": "^6.4.1",
144
149
  "rollup-plugin-filesize": "^10.0.0",
145
150
  "typescript": "^5.9.3"
146
151
  },
package/types/index.d.ts CHANGED
@@ -1,3 +1,64 @@
1
+ /**
2
+ * 处理数据库菜单项,生成 UI 菜单树和路由配置。
3
+ *
4
+ * @param {Array<Object>} menuItems - 原始菜单项数组,树形结构
5
+ * @param {Object} [options] - 配置选项
6
+ * @param {string} [options.idKey='id'] - 数据源 ID 键名
7
+ * @param {string} [options.codeKey='code'] - 数据源编码键名, 用于拼接路由名称和路由路径
8
+ * @param {string} [options.labelKey='text'] - 数据源标签键名
9
+ * @param {string} [options.childrenKey='children'] - 数据源子节点键名
10
+ * @param {string} [options.extendKey='extend'] - 数据源扩展对象键名
11
+ * @param {string} [options.menuIdKey='key'] - 输出菜单 ID 键名
12
+ * @param {string} [options.menuLabelKey='label'] - 输出菜单标签键名
13
+ * @param {string} [options.menuChildrenKey='children'] - 输出菜单子节点键名
14
+ * @param {string} [options.menuExtendKey='extend'] - 输出菜单扩展对象键名
15
+ * @param {string} [options.routeNameKey='name'] - 路由名称键名
16
+ * @param {string} [options.routePathKey='path'] - 路由路径键名
17
+ * @param {string} [options.routeMetaKey='meta'] - 路由元数据键名
18
+ * @param {Function} [options.handleNodeItem] - 节点处理钩子,参数:(nodeSimple) => void
19
+ * @param {Function} [options.handleMenuItem] - 菜单项处理钩子,参数:(uiMenuItem, nodeSimple) => void
20
+ * @param {Function} [options.handleRouteItem] - 路由项处理钩子,参数:(routeItem, nodeSimple) => void
21
+ *
22
+ * @returns {Object} 处理结果
23
+ * @returns {Array<Object>} returns.uiMenuItems - UI 菜单树形结构数组
24
+ * @returns {Array<Object>} returns.routeItems - 扁平化路由配置数组
25
+ * @returns {Map<string, Object>} returns.nodeMap - 节点 ID 到节点数据的映射表
26
+ *
27
+ * @example
28
+ * const menuItems = [
29
+ * { id: '1', code: 'system', text: '系统管理', children: [
30
+ * { id: '1-1', code: 'user', text: '用户管理' }
31
+ * ]}
32
+ * ];
33
+ *
34
+ * const result = handleDbMenuItems(menuItems, {
35
+ * handleRouteItem: (route, node) => {
36
+ * route.component = () => import(`./views/${node.code}.vue`);
37
+ * }
38
+ * });
39
+ *
40
+ * // result.uiMenuItems: [{ key: '1', label: '系统管理', children: [...] }]
41
+ * // result.routeItems: [{ name: 'system.user', path: '/system/user', meta: { id: '1-1' } }]
42
+ * // result.nodeMap: Map { '1' => {...}, '1-1' => {...} }
43
+ */
44
+ declare function handleDbMenuItems(menuItems: Array<Object>, options?: {
45
+ idKey?: string | undefined;
46
+ codeKey?: string | undefined;
47
+ labelKey?: string | undefined;
48
+ childrenKey?: string | undefined;
49
+ extendKey?: string | undefined;
50
+ menuIdKey?: string | undefined;
51
+ menuLabelKey?: string | undefined;
52
+ menuChildrenKey?: string | undefined;
53
+ menuExtendKey?: string | undefined;
54
+ routeNameKey?: string | undefined;
55
+ routePathKey?: string | undefined;
56
+ routeMetaKey?: string | undefined;
57
+ handleNodeItem?: Function | undefined;
58
+ handleMenuItem?: Function | undefined;
59
+ handleRouteItem?: Function | undefined;
60
+ }): Object;
61
+
1
62
  /**
2
63
  * 基于 `setTimeout` 的“间隔循环”定时器。
3
64
  * 每次任务执行完成后才计算下一次间隔,避免任务堆积。
@@ -881,6 +942,18 @@ declare function flatCompleteTree2NestedTree<T>(nodes: T[], parentId?: number |
881
942
  parentKey?: string | undefined;
882
943
  childrenKey?: string | undefined;
883
944
  }): (T & { [k in typeof childrenKey]: T[]; })[];
945
+ /**
946
+ * 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。
947
+ *
948
+ * @template T extends Record<PropertyKey, any>
949
+ * @param {string | number} id - 要查找的 id
950
+ * @param {T[]} arr - 嵌套树森林
951
+ * @param {string} [resultKey='name'] - 需要返回的字段
952
+ * @param {string} [idKey='id'] - 主键字段
953
+ * @param {string} [childrenKey='children'] - 子节点字段
954
+ * @returns {any} 找到的值;未找到返回 `undefined`
955
+ */
956
+ declare function findObjAttrValueById<T>(id: string | number, arr: T[], resultKey?: string, idKey?: string, childrenKey?: string): any;
884
957
  /**
885
958
  * 从服务端返回的已选 id 数组里,提取出
886
959
  * 1. 叶子节点
@@ -897,6 +970,6 @@ declare function extractFullyCheckedKeys(treeData: any[], selectedKeys: any[], i
897
970
  checked: string[];
898
971
  halfChecked: string[];
899
972
  };
900
- declare function findObjAttrValueById<T>(id: string | number, arr: T[], resultKey?: string, idKey?: string, childrenKey?: string): any;
973
+ declare function findTreeNodeById<T>(id: string | number, arr: T[], idKey?: string, childrenKey?: string): any;
901
974
 
902
- export { AudioStreamResampler, IntervalTimer, MyEvent, MyEvent_CrossPagePlugin, MyId, WebSocketManager, assignExisting, debounce, deepCloneByJSON, downloadByBlob, downloadByData, downloadByUrl, downloadExcel, downloadJSON, extractFullyCheckedKeys, fetchOrDownloadByUrl, findObjAttrValueById, flatCompleteTree2NestedTree, formatTimeForLocale, getAllSearchParams, getDataType, getFunctionArgNames, getGUID, getSearchParam, getTimePeriodName, getViewportSize, isBlob, isDate, isFunction, isNonEmptyString, isPlainObject, isPromise, millisecond2Duration, millisecond2DurationMaxDay, millisecond2DurationMaxHour, moveItem, nestedTree2IdMap, pcmToWavBlob, randomDateInRange, randomEnLetter, randomHan, randomHanOrEn, randomIntInRange, readBlobAsText, second2Duration, second2DurationMaxDay, second2DurationMaxHour, shuffle, throttle, toDate };
975
+ export { AudioStreamResampler, IntervalTimer, MyEvent, MyEvent_CrossPagePlugin, MyId, WebSocketManager, assignExisting, debounce, deepCloneByJSON, downloadByBlob, downloadByData, downloadByUrl, downloadExcel, downloadJSON, extractFullyCheckedKeys, fetchOrDownloadByUrl, findObjAttrValueById, findTreeNodeById, flatCompleteTree2NestedTree, formatTimeForLocale, getAllSearchParams, getDataType, getFunctionArgNames, getGUID, getSearchParam, getTimePeriodName, getViewportSize, handleDbMenuItems, isBlob, isDate, isFunction, isNonEmptyString, isPlainObject, isPromise, millisecond2Duration, millisecond2DurationMaxDay, millisecond2DurationMaxHour, moveItem, nestedTree2IdMap, pcmToWavBlob, randomDateInRange, randomEnLetter, randomHan, randomHanOrEn, randomIntInRange, readBlobAsText, second2Duration, second2DurationMaxDay, second2DurationMaxHour, shuffle, throttle, toDate };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * 处理数据库菜单项,生成 UI 菜单树和路由配置。
3
+ *
4
+ * @param {Array<Object>} menuItems - 原始菜单项数组,树形结构
5
+ * @param {Object} [options] - 配置选项
6
+ * @param {string} [options.idKey='id'] - 数据源 ID 键名
7
+ * @param {string} [options.codeKey='code'] - 数据源编码键名, 用于拼接路由名称和路由路径
8
+ * @param {string} [options.labelKey='text'] - 数据源标签键名
9
+ * @param {string} [options.childrenKey='children'] - 数据源子节点键名
10
+ * @param {string} [options.extendKey='extend'] - 数据源扩展对象键名
11
+ * @param {string} [options.menuIdKey='key'] - 输出菜单 ID 键名
12
+ * @param {string} [options.menuLabelKey='label'] - 输出菜单标签键名
13
+ * @param {string} [options.menuChildrenKey='children'] - 输出菜单子节点键名
14
+ * @param {string} [options.menuExtendKey='extend'] - 输出菜单扩展对象键名
15
+ * @param {string} [options.routeNameKey='name'] - 路由名称键名
16
+ * @param {string} [options.routePathKey='path'] - 路由路径键名
17
+ * @param {string} [options.routeMetaKey='meta'] - 路由元数据键名
18
+ * @param {Function} [options.handleNodeItem] - 节点处理钩子,参数:(nodeSimple) => void
19
+ * @param {Function} [options.handleMenuItem] - 菜单项处理钩子,参数:(uiMenuItem, nodeSimple) => void
20
+ * @param {Function} [options.handleRouteItem] - 路由项处理钩子,参数:(routeItem, nodeSimple) => void
21
+ *
22
+ * @returns {Object} 处理结果
23
+ * @returns {Array<Object>} returns.uiMenuItems - UI 菜单树形结构数组
24
+ * @returns {Array<Object>} returns.routeItems - 扁平化路由配置数组
25
+ * @returns {Map<string, Object>} returns.nodeMap - 节点 ID 到节点数据的映射表
26
+ *
27
+ * @example
28
+ * const menuItems = [
29
+ * { id: '1', code: 'system', text: '系统管理', children: [
30
+ * { id: '1-1', code: 'user', text: '用户管理' }
31
+ * ]}
32
+ * ];
33
+ *
34
+ * const result = handleDbMenuItems(menuItems, {
35
+ * handleRouteItem: (route, node) => {
36
+ * route.component = () => import(`./views/${node.code}.vue`);
37
+ * }
38
+ * });
39
+ *
40
+ * // result.uiMenuItems: [{ key: '1', label: '系统管理', children: [...] }]
41
+ * // result.routeItems: [{ name: 'system.user', path: '/system/user', meta: { id: '1-1' } }]
42
+ * // result.nodeMap: Map { '1' => {...}, '1-1' => {...} }
43
+ */
44
+ declare function handleDbMenuItems(menuItems: Array<Object>, options?: {
45
+ idKey?: string | undefined;
46
+ codeKey?: string | undefined;
47
+ labelKey?: string | undefined;
48
+ childrenKey?: string | undefined;
49
+ extendKey?: string | undefined;
50
+ menuIdKey?: string | undefined;
51
+ menuLabelKey?: string | undefined;
52
+ menuChildrenKey?: string | undefined;
53
+ menuExtendKey?: string | undefined;
54
+ routeNameKey?: string | undefined;
55
+ routePathKey?: string | undefined;
56
+ routeMetaKey?: string | undefined;
57
+ handleNodeItem?: Function | undefined;
58
+ handleMenuItem?: Function | undefined;
59
+ handleRouteItem?: Function | undefined;
60
+ }): Object;
61
+
62
+ export { handleDbMenuItems };
package/types/tree.d.ts CHANGED
@@ -25,6 +25,18 @@ declare function flatCompleteTree2NestedTree<T>(nodes: T[], parentId?: number |
25
25
  parentKey?: string | undefined;
26
26
  childrenKey?: string | undefined;
27
27
  }): (T & { [k in typeof childrenKey]: T[]; })[];
28
+ /**
29
+ * 在嵌套树中按 `id` 递归查找节点,并返回其指定属性值。
30
+ *
31
+ * @template T extends Record<PropertyKey, any>
32
+ * @param {string | number} id - 要查找的 id
33
+ * @param {T[]} arr - 嵌套树森林
34
+ * @param {string} [resultKey='name'] - 需要返回的字段
35
+ * @param {string} [idKey='id'] - 主键字段
36
+ * @param {string} [childrenKey='children'] - 子节点字段
37
+ * @returns {any} 找到的值;未找到返回 `undefined`
38
+ */
39
+ declare function findObjAttrValueById<T>(id: string | number, arr: T[], resultKey?: string, idKey?: string, childrenKey?: string): any;
28
40
  /**
29
41
  * 从服务端返回的已选 id 数组里,提取出
30
42
  * 1. 叶子节点
@@ -41,6 +53,6 @@ declare function extractFullyCheckedKeys(treeData: any[], selectedKeys: any[], i
41
53
  checked: string[];
42
54
  halfChecked: string[];
43
55
  };
44
- declare function findObjAttrValueById<T>(id: string | number, arr: T[], resultKey?: string, idKey?: string, childrenKey?: string): any;
56
+ declare function findTreeNodeById<T>(id: string | number, arr: T[], idKey?: string, childrenKey?: string): any;
45
57
 
46
- export { extractFullyCheckedKeys, findObjAttrValueById, flatCompleteTree2NestedTree, nestedTree2IdMap };
58
+ export { extractFullyCheckedKeys, findObjAttrValueById, findTreeNodeById, flatCompleteTree2NestedTree, nestedTree2IdMap };