utils.ts 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * @Author: your name
  3. * @Date: 2022-01-13 17:09:05
  4. * @LastEditTime: 2025-04-17 11:01:43
  5. * @LastEditors: code4eat awesomedema@gmail.com
  6. * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  7. * @FilePath: /KC-MiddlePlatform/src/utils.js
  8. */
  9. import axios, { AxiosResponse } from 'axios';
  10. import { Key } from 'react';
  11. /**
  12. * 生成指定长度的随机字符串
  13. * @param length 字符串长度
  14. * @returns 随机字符串
  15. */
  16. export const randomString = (length: number): string => {
  17. const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_=-';
  18. return Array.from(
  19. { length },
  20. () => chars[Math.floor(Math.random() * chars.length)]
  21. ).join('');
  22. };
  23. export interface TreeItemType {
  24. children?: TreeItemType[];
  25. [key: string]: any;
  26. }
  27. /**
  28. * 从树结构中获取指定键的所有值
  29. * @param data 树结构数据
  30. * @param key 要获取的键名
  31. * @returns 值的数组
  32. */
  33. export const getValsFromTree = (data: TreeItemType[], key: string): any[] => {
  34. const result: any[] = [];
  35. const traverse = (nodes: TreeItemType[]): void => {
  36. nodes.forEach((node) => {
  37. if (node[key]) {
  38. result.push(node[key]);
  39. }
  40. if (node.children?.length) {
  41. traverse(node.children);
  42. }
  43. });
  44. };
  45. traverse(data);
  46. return result;
  47. };
  48. export const searchTree = (treeData: TreeItemType[]) => {};
  49. /**
  50. * 下载模板文件
  51. * @param path 文件路径
  52. */
  53. export const downloadTemplateReq = async (path: string): Promise<void> => {
  54. try {
  55. const userData = localStorage.getItem('userData');
  56. const { token = '' } = JSON.parse(userData || '{}');
  57. const response: AxiosResponse = await axios({
  58. method: 'get',
  59. url: `/gateway/${path}`,
  60. responseType: 'blob',
  61. headers: { token },
  62. });
  63. const filename = decodeURI(response.headers['content-disposition']);
  64. const blob = new Blob([response.data], {
  65. type: 'application/vnd.ms-excel',
  66. });
  67. const objectUrl = URL.createObjectURL(blob);
  68. const link = document.createElement('a');
  69. link.download = `${filename}.xls`;
  70. link.href = objectUrl;
  71. link.style.display = 'none';
  72. document.body.appendChild(link);
  73. link.click();
  74. document.body.removeChild(link);
  75. URL.revokeObjectURL(objectUrl);
  76. } catch (error) {
  77. console.error('下载模板失败:', error);
  78. throw error;
  79. }
  80. };
  81. /**
  82. * 获取树结构中最深的节点及其父节点
  83. * @param tree 树结构
  84. * @param childrenName 子节点属性名
  85. * @returns [最深节点, 父节点]
  86. */
  87. export const getDeepestTreeData = <T extends { [key: string]: any }>(
  88. tree: T,
  89. childrenName: string
  90. ): [T, T | undefined] => {
  91. let parent: T | undefined;
  92. const traverse = (node: T): T => {
  93. if (node[childrenName]?.length) {
  94. parent = node;
  95. return traverse(node[childrenName][0]);
  96. }
  97. return node;
  98. };
  99. return [traverse(tree), parent];
  100. };
  101. /**
  102. * 数组去重
  103. * @param arr 数组
  104. * @param uniId 唯一标识字段
  105. * @returns 去重后的数组
  106. */
  107. export const uniqueFunc = <T extends { [key: string]: any }>(arr: T[], uniId: string): T[] => {
  108. const uniqueMap = new Map();
  109. return arr.filter((item) => !uniqueMap.has(item[uniId]) && uniqueMap.set(item[uniId], 1));
  110. };
  111. //获取树结构的所有叶子节点
  112. interface TreeNode {
  113. [key: string]: any;
  114. child?: TreeNode[];
  115. }
  116. /**
  117. * 获取树的所有叶子节点
  118. * @param node 树节点
  119. * @param leaves 叶子节点数组
  120. * @returns 叶子节点数组
  121. */
  122. export const getLeafNodes = (node: TreeNode, leaves: TreeNode[] = []): TreeNode[] => {
  123. if (!node.child?.length) {
  124. leaves.push(node);
  125. } else {
  126. node.child.forEach((child) => getLeafNodes(child, leaves));
  127. }
  128. return leaves;
  129. };
  130. //根据树结构中的某个属性的集合,获取对应的节点,返回一个集合
  131. /**
  132. * 根据属性值查找节点
  133. * @param node 树节点
  134. * @param keys 属性值集合
  135. * @param str 属性名
  136. * @returns 匹配的节点数组
  137. */
  138. export const findNodesBySomes = (
  139. node: TreeNode,
  140. keys: Set<string | number>,
  141. str: string
  142. ): TreeNode[] => {
  143. const results: TreeNode[] = [];
  144. if (keys.has(node[str])) {
  145. results.push(node);
  146. }
  147. if (node.child?.length) {
  148. node.child.forEach((child) => {
  149. results.push(...findNodesBySomes(child, keys, str));
  150. });
  151. }
  152. return results;
  153. };
  154. //更改树结构集合的子集属性名
  155. /**
  156. * 重命名子节点属性
  157. * @param nodes 节点数组
  158. * @param key 要重命名的属性名
  159. * @returns 处理后的节点数组
  160. */
  161. export const renameChildListToChildren = <T extends { [key: string]: any; children?: T[] }>(
  162. nodes: T[],
  163. key: string
  164. ): T[] => {
  165. return nodes.map((node) => {
  166. const newNode = { ...node };
  167. if (newNode[key]?.length) {
  168. newNode.children = renameChildListToChildren(newNode[key], key);
  169. }
  170. return newNode;
  171. });
  172. };
  173. //获取目标节点的所有父节点,且以集合的方式返回
  174. /**
  175. * 查找节点的所有父节点
  176. * @param tree 树结构
  177. * @param targetNodeKeyName 目标节点键名
  178. * @param targetNodeKeyVal 目标节点键值
  179. * @param path 路径
  180. * @returns 父节点数组或null
  181. */
  182. export const findParents = (
  183. tree: TreeNode[],
  184. targetNodeKeyName: string,
  185. targetNodeKeyVal: Key,
  186. path: TreeNode[] = []
  187. ): TreeNode[] | null => {
  188. for (const node of tree) {
  189. if (node[targetNodeKeyName] === targetNodeKeyVal) {
  190. return [...path, node];
  191. }
  192. if (node.children?.length) {
  193. const result = findParents(node.children, targetNodeKeyName, targetNodeKeyVal, [...path, node]);
  194. if (result) return result;
  195. }
  196. }
  197. return null;
  198. };
  199. //搜索树结果
  200. /**
  201. * 搜索树结构并保持结构
  202. * @param nodes 节点数组
  203. * @param keyName 键名
  204. * @param keyVal 键值
  205. * @returns 匹配的节点数组
  206. */
  207. export const searchTreeAndKeepStructure = <T extends { [key: string]: any }>(
  208. nodes: T[],
  209. keyName: string,
  210. keyVal: any
  211. ): T[] => {
  212. return nodes.reduce<T[]>((result, node) => {
  213. if (String(node[keyName]).includes(String(keyVal))) {
  214. result.push({
  215. ...node,
  216. children: node.children?.length
  217. ? searchTreeAndKeepStructure(node.children, keyName, keyVal)
  218. : undefined,
  219. });
  220. } else if (node.children?.length) {
  221. const children = searchTreeAndKeepStructure(node.children, keyName, keyVal);
  222. if (children.length) {
  223. result.push({ ...node, children });
  224. }
  225. }
  226. return result;
  227. }, []);
  228. };