index.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. import { h, unref } from 'vue';
  2. import type { App, Plugin } from 'vue';
  3. import { ElIcon, ElTag } from 'element-plus';
  4. import { PageEnum } from '@/enums/pageEnum';
  5. import { isObject, isString, isNumber } from './is/index';
  6. import { cloneDeep } from 'lodash-es';
  7. import { TargetContext } from '/#/index';
  8. /**
  9. * render 图标
  10. * */
  11. export function renderIcon(icon) {
  12. return () => h(ElIcon, null, { default: () => h(icon) });
  13. }
  14. /**
  15. * render 图片
  16. * */
  17. export function renderImg(imgSrc: string) {
  18. return () => h('img', { src: imgSrc, class: 'my-icon' });
  19. }
  20. /**
  21. * render new Tag
  22. * */
  23. const newTagColors = { color: '#f90', textColor: '#fff', borderColor: '#f90' };
  24. export function renderNew(type = 'warning', text = 'New', color: object = newTagColors) {
  25. return () =>
  26. h(
  27. ElTag as any,
  28. {
  29. type,
  30. round: true,
  31. size: 'small',
  32. color,
  33. },
  34. { default: () => text },
  35. );
  36. }
  37. /**
  38. * 递归组装菜单格式
  39. */
  40. export function generatorMenu(routerMap: Array<any>) {
  41. return filterRouter(routerMap).map((item) => {
  42. const isRoot = isRootRouter(item);
  43. const info = isRoot ? item.children[0] : item;
  44. const currentMenu = {
  45. ...info,
  46. ...info.meta,
  47. title: info.meta?.title,
  48. key: info.name,
  49. icon: isRoot ? item.meta?.icon : info.meta?.icon,
  50. };
  51. // 是否有子菜单,并递归处理
  52. if (info.children && info.children.length > 0) {
  53. // Recursion
  54. currentMenu.children = generatorMenu(info.children);
  55. }
  56. return currentMenu;
  57. });
  58. }
  59. /**
  60. * 混合菜单
  61. * */
  62. export function generatorMenuMix(routerMap: Array<any>, routerName: string, location: string) {
  63. const cloneRouterMap = cloneDeep(routerMap);
  64. const newRouter = filterRouter(cloneRouterMap);
  65. if (location === 'header') {
  66. const firstRouter: any[] = [];
  67. newRouter.forEach((item) => {
  68. const isRoot = isRootRouter(item);
  69. const info = isRoot ? item.children[0] : item;
  70. info.children = undefined;
  71. const currentMenu = {
  72. ...info,
  73. ...info.meta,
  74. title: info.meta?.title,
  75. key: info.name,
  76. };
  77. firstRouter.push(currentMenu);
  78. });
  79. console.log(firstRouter);
  80. return firstRouter;
  81. } else {
  82. const currentRouters = newRouter.filter((item) => item.name === routerName);
  83. const childrenRouter = currentRouters.length ? currentRouters[0].children || [] : [];
  84. return getChildrenRouter(childrenRouter);
  85. }
  86. }
  87. /**
  88. * 递归组装子菜单
  89. * */
  90. export function getChildrenRouter(routerMap: Array<any>) {
  91. return filterRouter(routerMap).map((item) => {
  92. const isRoot = isRootRouter(item);
  93. const info = isRoot ? item.children[0] : item;
  94. const currentMenu = {
  95. ...info,
  96. ...info.meta,
  97. title: info.meta?.title,
  98. key: info.name,
  99. };
  100. // 是否有子菜单,并递归处理
  101. if (info.children && info.children.length > 0) {
  102. // Recursion
  103. currentMenu.children = getChildrenRouter(info.children);
  104. }
  105. return currentMenu;
  106. });
  107. }
  108. /**
  109. * 判断根路由 Router
  110. * */
  111. export function isRootRouter(item) {
  112. return item.meta?.alwaysShow === true && item.children?.length === 1;
  113. }
  114. /**
  115. * 排除Router
  116. * */
  117. export function filterRouter(routerMap: Array<any>) {
  118. return routerMap.filter((item) => {
  119. return (
  120. (item.meta?.hidden || false) != true &&
  121. !['/:path(.*)*', '/', PageEnum.REDIRECT, PageEnum.BASE_LOGIN].includes(item.path)
  122. );
  123. });
  124. }
  125. export const withInstall = <T>(component: T, alias?: string) => {
  126. const comp = component as any;
  127. comp.install = (app: App) => {
  128. app.component(comp.name || comp.displayName, component);
  129. if (alias) {
  130. app.config.globalProperties[alias] = component;
  131. }
  132. };
  133. return component as T & Plugin;
  134. };
  135. /**
  136. * 找到对应的节点
  137. * */
  138. let result = null;
  139. export function getTreeItem(data: any[], key?: string | number, keyField = 'key'): any {
  140. data.map((item) => {
  141. if (item[keyField] === key) {
  142. result = item;
  143. } else {
  144. if (item.children && item.children.length) {
  145. getTreeItem(item.children, key, keyField);
  146. }
  147. }
  148. });
  149. return result;
  150. }
  151. /**
  152. * 找到所有节点
  153. * */
  154. const treeAll: any[] = [];
  155. export function getTreeAll(data: any[]): any[] {
  156. data.map((item) => {
  157. treeAll.push(item.key);
  158. if (item.children && item.children.length) {
  159. getTreeAll(item.children);
  160. }
  161. });
  162. return treeAll;
  163. }
  164. // dynamic use hook props
  165. export function getDynamicProps<T, U>(props: T): Partial<U> {
  166. const ret: Recordable = {};
  167. Object.keys(props).map((key) => {
  168. ret[key] = unref((props as Recordable)[key]);
  169. });
  170. return ret as Partial<U>;
  171. }
  172. export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
  173. let key: string;
  174. for (key in target) {
  175. src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key]);
  176. }
  177. return src;
  178. }
  179. /**
  180. * Sums the passed percentage to the R, G or B of a HEX color
  181. * @param {string} color The color to change
  182. * @param {number} amount The amount to change the color by
  183. * @returns {string} The processed part of the color
  184. */
  185. function addLight(color: string, amount: number) {
  186. const cc = parseInt(color, 16) + amount;
  187. const c = cc > 255 ? 255 : cc;
  188. return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
  189. }
  190. /**
  191. * Lightens a 6 char HEX color according to the passed percentage
  192. * @param {string} color The color to change
  193. * @param {number} amount The amount to change the color by
  194. * @returns {string} The processed color represented as HEX
  195. */
  196. export function lighten(color: string, amount: number) {
  197. color = color.indexOf('#') >= 0 ? color.substring(1, color.length) : color;
  198. amount = Math.trunc((255 * amount) / 100);
  199. return `#${addLight(color.substring(0, 2), amount)}${addLight(
  200. color.substring(2, 4),
  201. amount,
  202. )}${addLight(color.substring(4, 6), amount)}`;
  203. }
  204. export function openWindow(
  205. url: string,
  206. opt?: { target?: TargetContext | string; noopener?: boolean; noreferrer?: boolean },
  207. ) {
  208. const { target = '__blank', noopener = true, noreferrer = true } = opt || {};
  209. const feature: string[] = [];
  210. noopener && feature.push('noopener=yes');
  211. noreferrer && feature.push('noreferrer=yes');
  212. window.open(url, target, feature.join(','));
  213. }
  214. /**
  215. * 处理css单位
  216. * */
  217. export function cssUnit(value: string | number, unit = 'px') {
  218. return isNumber(value) || (isString(value) && value.indexOf(unit as string) === -1)
  219. ? `${value}${unit}`
  220. : value;
  221. }
  222. /**
  223. * 判断是否 url
  224. * */
  225. export function isUrl(url: string) {
  226. return /^(http|https):\/\//g.test(url);
  227. }
  228. /*
  229. * 模拟a下载一个文件
  230. * @params res 结果集
  231. * @params filename 文件名
  232. */
  233. export const downloadFile = (res, filename?) => {
  234. const blob = new Blob([res.data]);
  235. let fileName = filename || res.headers['content-disposition'].split('filename=').pop();
  236. fileName = decodeURIComponent(fileName);
  237. if (window.navigator && window.navigator.msSaveOrOpenBlob) {
  238. // IE
  239. window.navigator.msSaveOrOpenBlob(blob, fileName);
  240. } else {
  241. const objectUrl = (window.URL || window.webkitURL).createObjectURL(blob);
  242. const downFile = document.createElement('a');
  243. downFile.style.display = 'none';
  244. downFile.href = objectUrl;
  245. downFile.download = fileName; // 下载后文件名
  246. document.body.appendChild(downFile);
  247. downFile.click();
  248. document.body.removeChild(downFile); // 下载完成移除元素
  249. window.URL.revokeObjectURL(objectUrl); // 释放掉blob对象。
  250. }
  251. };