other.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import { nextTick, defineAsyncComponent } from 'vue';
  2. import type { App } from 'vue';
  3. import * as svg from '@element-plus/icons-vue';
  4. import router from '/@/router/index';
  5. import pinia from '/@/stores/index';
  6. import { storeToRefs } from 'pinia';
  7. import { useThemeConfig } from '/@/stores/themeConfig';
  8. import { i18n } from '/@/i18n/index';
  9. import { Local } from '/@/utils/storage';
  10. import { verifyUrl } from '/@/utils/toolsValidate';
  11. import {SystemConfigStore} from "/@/stores/systemConfig";
  12. // 引入组件
  13. const SvgIcon = defineAsyncComponent(() => import('/@/components/svgIcon/index.vue'));
  14. /**
  15. * 导出全局注册 element plus svg 图标
  16. * @param app vue 实例
  17. * @description 使用:https://element-plus.gitee.io/zh-CN/component/icon.html
  18. */
  19. export function elSvg(app: App) {
  20. const icons = svg as any;
  21. for (const i in icons) {
  22. app.component(`ele-${icons[i].name}`, icons[i]);
  23. }
  24. app.component('SvgIcon', SvgIcon);
  25. }
  26. /**
  27. * 设置浏览器标题国际化
  28. * @method const title = useTitle(); ==> title()
  29. */
  30. export function useTitle() {
  31. const stores = SystemConfigStore(pinia);
  32. const { systemConfig }: { systemConfig: any} = storeToRefs(stores);
  33. nextTick(() => {
  34. let webTitle = '';
  35. let globalTitle: string = systemConfig['base.web_title'];
  36. const { path, meta } = router.currentRoute.value;
  37. if (path === '/login') {
  38. webTitle = <string>meta.title;
  39. } else {
  40. webTitle = setTagsViewNameI18n(router.currentRoute.value);
  41. }
  42. // document.title = `${webTitle} - ${globalTitle}` || "DVAdmin";
  43. document.title = `${webTitle}`;
  44. });
  45. }
  46. /***
  47. * 设置网站favicon图标
  48. */
  49. export function useFavicon() {
  50. const stores = SystemConfigStore(pinia);
  51. const { systemConfig } = storeToRefs(stores);
  52. nextTick(() => {
  53. const iconUrl = systemConfig.value['base.web_favicon']
  54. if(iconUrl){
  55. // 动态设置 favicon,这里假设 favicon 的 URL 是动态获取的或从变量中来
  56. const faviconUrl = `${iconUrl}?t=${new Date().getTime()}`;
  57. const link = document.querySelector("link[rel~='icon']") as HTMLLinkElement;
  58. if (!link) {
  59. const newLink = document.createElement('link') as HTMLLinkElement;
  60. newLink.rel = 'shortcut icon';
  61. newLink.href = faviconUrl;
  62. document.head.appendChild(newLink);
  63. } else {
  64. link.href = faviconUrl;
  65. }
  66. }
  67. });
  68. }
  69. /**
  70. * 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
  71. * @param params 路由 query、params 中的 tagsViewName
  72. * @returns 返回当前 tagsViewName 名称
  73. */
  74. export function setTagsViewNameI18n(item: any) {
  75. let tagsViewName: string = '';
  76. const { query, params, meta } = item;
  77. if (query?.tagsViewName || params?.tagsViewName) {
  78. if (/\/zh-cn|en|zh-tw\//.test(query?.tagsViewName) || /\/zh-cn|en|zh-tw\//.test(params?.tagsViewName)) {
  79. // 国际化
  80. const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
  81. tagsViewName = urlTagsParams[i18n.global.locale.value];
  82. } else {
  83. // 非国际化
  84. tagsViewName = query?.tagsViewName || params?.tagsViewName;
  85. }
  86. } else {
  87. // 非自定义 tagsView 名称
  88. tagsViewName = i18n.global.t(meta.title);
  89. }
  90. return tagsViewName;
  91. }
  92. /**
  93. * 图片懒加载
  94. * @param el dom 目标元素
  95. * @param arr 列表数据
  96. * @description data-xxx 属性用于存储页面或应用程序的私有自定义数据
  97. */
  98. export const lazyImg = (el: string, arr: EmptyArrayType) => {
  99. const io = new IntersectionObserver((res) => {
  100. res.forEach((v: any) => {
  101. if (v.isIntersecting) {
  102. const { img, key } = v.target.dataset;
  103. v.target.src = img;
  104. v.target.onload = () => {
  105. io.unobserve(v.target);
  106. arr[key]['loading'] = false;
  107. };
  108. }
  109. });
  110. });
  111. nextTick(() => {
  112. document.querySelectorAll(el).forEach((img) => io.observe(img));
  113. });
  114. };
  115. /**
  116. * 全局组件大小
  117. * @returns 返回 `window.localStorage` 中读取的缓存值 `globalComponentSize`
  118. */
  119. export const globalComponentSize = (): string => {
  120. const stores = useThemeConfig(pinia);
  121. const { themeConfig } = storeToRefs(stores);
  122. return Local.get('themeConfig')?.globalComponentSize || themeConfig.value?.globalComponentSize;
  123. };
  124. /**
  125. * 对象深克隆
  126. * @param obj 源对象
  127. * @returns 克隆后的对象
  128. */
  129. export function deepClone(obj: EmptyObjectType) {
  130. let newObj: EmptyObjectType;
  131. try {
  132. newObj = obj.push ? [] : {};
  133. } catch (error) {
  134. newObj = {};
  135. }
  136. for (let attr in obj) {
  137. if (obj[attr] && typeof obj[attr] === 'object') {
  138. newObj[attr] = deepClone(obj[attr]);
  139. } else {
  140. newObj[attr] = obj[attr];
  141. }
  142. }
  143. return newObj;
  144. }
  145. /**
  146. * 判断是否是移动端
  147. */
  148. export function isMobile() {
  149. if (
  150. navigator.userAgent.match(
  151. /('phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone')/i
  152. )
  153. ) {
  154. return true;
  155. } else {
  156. return false;
  157. }
  158. }
  159. /**
  160. * 判断数组对象中所有属性是否为空,为空则删除当前行对象
  161. * @description @感谢大黄
  162. * @param list 数组对象
  163. * @returns 删除空值后的数组对象
  164. */
  165. export function handleEmpty(list: EmptyArrayType) {
  166. const arr = [];
  167. for (const i in list) {
  168. const d = [];
  169. for (const j in list[i]) {
  170. d.push(list[i][j]);
  171. }
  172. const leng = d.filter((item) => item === '').length;
  173. if (leng !== d.length) {
  174. arr.push(list[i]);
  175. }
  176. }
  177. return arr;
  178. }
  179. /**
  180. * 打开外部链接
  181. * @param val 当前点击项菜单
  182. */
  183. export function handleOpenLink(val: RouteItem) {
  184. const { origin, pathname } = window.location;
  185. router.push(val.path);
  186. if (verifyUrl(<string>val.meta?.isLink)) window.open(val.meta?.isLink);
  187. else window.open(`${origin}${pathname}#${val.meta?.isLink}`);
  188. }
  189. /**
  190. * 统一批量导出
  191. * @method elSvg 导出全局注册 element plus svg 图标
  192. * @method useTitle 设置浏览器标题国际化
  193. * @method setTagsViewNameI18n 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
  194. * @method lazyImg 图片懒加载
  195. * @method globalComponentSize() element plus 全局组件大小
  196. * @method deepClone 对象深克隆
  197. * @method isMobile 判断是否是移动端
  198. * @method handleEmpty 判断数组对象中所有属性是否为空,为空则删除当前行对象
  199. * @method handleOpenLink 打开外部链接
  200. */
  201. const other = {
  202. elSvg: (app: App) => {
  203. elSvg(app);
  204. },
  205. useTitle: () => {
  206. useTitle();
  207. },
  208. useFavicon:()=>{
  209. useFavicon()
  210. },
  211. setTagsViewNameI18n(route: RouteToFrom) {
  212. return setTagsViewNameI18n(route);
  213. },
  214. lazyImg: (el: string, arr: EmptyArrayType) => {
  215. lazyImg(el, arr);
  216. },
  217. globalComponentSize: () => {
  218. return globalComponentSize();
  219. },
  220. deepClone: (obj: EmptyObjectType) => {
  221. return deepClone(obj);
  222. },
  223. isMobile: () => {
  224. return isMobile();
  225. },
  226. handleEmpty: (list: EmptyArrayType) => {
  227. return handleEmpty(list);
  228. },
  229. handleOpenLink: (val: RouteItem) => {
  230. handleOpenLink(val);
  231. },
  232. };
  233. // 统一批量导出
  234. export default other;