| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- import {nextTick, defineAsyncComponent} from 'vue';
- import type {App} from 'vue';
- import * as svg from '@element-plus/icons-vue';
- import router from '/@/router/index';
- import pinia from '/@/stores/index';
- import {storeToRefs} from 'pinia';
- import {useThemeConfig} from '/@/stores/themeConfig';
- import {i18n} from '/@/i18n/index';
- import {Local} from '/@/utils/storage';
- import {verifyUrl} from '/@/utils/toolsValidate';
- import request from '/@/utils/request';
- import {useMessage} from '/@/hooks/message';
- // @ts-ignore
- import * as CryptoJS from 'crypto-js';
- import {validateNull} from './validate';
- import {RouteItem, RouteItems, RouteToFrom} from "/@/types/global";
- // 引入组件
- const SvgIcon = defineAsyncComponent(() => import('/@/components/SvgIcon/index.vue'));
- /**
- * 导出全局注册 element plus svg 图标
- * @param app vue 实例
- * @description 使用:https://element-plus.gitee.io/zh-CN/component/icon.html
- */
- export function elSvg(app: App) {
- const icons = svg as any;
- for (const i in icons) {
- app.component(`ele-${icons[i].name}`, icons[i]);
- }
- app.component('SvgIcon', SvgIcon);
- }
- /**
- * 设置浏览器标题国际化
- * @method const title = useTitle(); ==> title()
- */
- export function useTitle() {
- const stores = useThemeConfig(pinia);
- const {themeConfig} = storeToRefs(stores);
- nextTick(() => {
- let globalTitle: string = themeConfig.value.globalTitle;
- let webTitle = setMenuI18n(router.currentRoute.value);
- document.title = `${webTitle} - ${globalTitle}` || globalTitle;
- });
- }
- /**
- * 设置菜单国际化
- * @param {object} item - 菜单项对象
- * @param {string} item.enName - 英文名称
- * @param {string} item.name - 名称
- * @returns {string} - 国际化后的名称
- */
- export function setMenuI18n(item: any) {
- let name = i18n.global.t(item.name)
- if (name !== item.name) {
- return name;
- }
- return i18n.global.locale.value === 'en' ? item.meta.enName : item.meta.title;
- }
- /**
- * 图片懒加载
- * @param el dom 目标元素
- * @param arr 列表数据
- * @description data-xxx 属性用于存储页面或应用程序的私有自定义数据
- */
- export const lazyImg = (el: string, arr: EmptyArrayType) => {
- const io = new IntersectionObserver((res) => {
- res.forEach((v: any) => {
- if (v.isIntersecting) {
- const {img, key} = v.target.dataset;
- v.target.src = img;
- v.target.onload = () => {
- io.unobserve(v.target);
- arr[key]['loading'] = false;
- };
- }
- });
- });
- nextTick(() => {
- document.querySelectorAll(el).forEach((img) => io.observe(img));
- });
- };
- /**
- * 全局组件大小
- * @returns 返回 `window.localStorage` 中读取的缓存值 `globalComponentSize`
- */
- export const globalComponentSize = (): string => {
- const stores = useThemeConfig(pinia);
- const {themeConfig} = storeToRefs(stores);
- return Local.get('themeConfig')?.globalComponentSize || themeConfig.value?.globalComponentSize;
- };
- /**
- * 对象深克隆
- * @param obj 源对象
- * @returns 克隆后的对象
- */
- export function deepClone(obj: EmptyObjectType) {
- let newObj: EmptyObjectType;
- try {
- newObj = obj.push ? [] : {};
- } catch (error) {
- newObj = {};
- }
- for (let attr in obj) {
- if (obj[attr] && typeof obj[attr] === 'object') {
- newObj[attr] = deepClone(obj[attr]);
- } else {
- newObj[attr] = obj[attr];
- }
- }
- return newObj;
- }
- /**
- * 判断是否是移动端
- */
- export function isMobile() {
- if (
- navigator.userAgent.match(
- /('phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone')/i
- )
- ) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * 判断数组对象中所有属性是否为空,为空则删除当前行对象
- * @description @感谢大黄
- * @param list 数组对象
- * @returns 删除空值后的数组对象
- */
- export function handleEmpty(list: EmptyArrayType) {
- const arr = [] as any[];
- for (const i in list) {
- const d = [] as any[];
- for (const j in list[i]) {
- d.push(list[i][j]);
- }
- const leng = d.filter((item) => item === '').length;
- if (leng !== d.length) {
- arr.push(list[i]);
- }
- }
- return arr;
- }
- /**
- * 打开外部链接
- * @param val 当前点击项菜单
- */
- export function handleOpenLink(val: RouteItem) {
- router.push(val.path);
- if (verifyUrl(<string>val.meta?.isLink)) window.open(val.meta?.isLink);
- else window.open(`${val.meta?.isLink}`);
- }
- /**
- * 打开小窗口
- */
- export const openWindow = (url: string, title: string, w: number, h: number) => {
- // @ts-ignore
- const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;
- // @ts-ignore
- const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;
- const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
- const height = window.innerHeight
- ? window.innerHeight
- : document.documentElement.clientHeight
- ? document.documentElement.clientHeight
- : screen.height;
- const left = width / 2 - w / 2 + dualScreenLeft;
- const top = height / 2 - h / 2 + dualScreenTop;
- return window.open(
- url,
- title,
- 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' +
- w +
- ', height=' +
- h +
- ', top=' +
- top +
- ', left=' +
- left
- );
- };
- /**
- *加密处理
- */
- export function encryption(src: string) {
- const key = CryptoJS.enc.Utf8.parse(import.meta.env.VITE_PWD_ENC_KEY);
- const iv = CryptoJS.enc.Utf8.parse(import.meta.env.VITE_PWD_ENC_IV);
- // 加密
- var encrypted = CryptoJS.AES.encrypt(src, key, {
- key: key,
- iv: iv,
- mode: CryptoJS.mode.CBC,
- padding: CryptoJS.pad.Pkcs7,
- });
- return encrypted.toString();
- }
- /**
- * 解密
- * @param {*} params 参数列表
- * @returns 明文
- */
- export function decryption(src: string) {
- const key = CryptoJS.enc.Utf8.parse(import.meta.env.VITE_PWD_ENC_KEY);
- const iv = CryptoJS.enc.Utf8.parse(import.meta.env.VITE_PWD_ENC_IV);
- // 解密逻辑
- var decryptd = CryptoJS.AES.decrypt(src, key, {
- key: key,
- iv: iv,
- mode: CryptoJS.mode.CBC,
- padding: CryptoJS.pad.Pkcs7,
- });
- return decryptd.toString(CryptoJS.enc.Utf8);
- }
- /**
- * Base64 加密
- * @param {*} src 明文
- * @returns 密文
- */
- export function base64Encrypt(src: string) {
- const encodedWord = CryptoJS.enc.Utf8.parse(src);
- return CryptoJS.enc.Base64.stringify(encodedWord);
- }
- /**
- *
- * @param url 目标下载接口
- * @param query 查询参数
- * @param fileName 文件名称
- * @returns {*}
- */
- export function downBlobFile(url: any, query: any, fileName: string) {
- return request({
- url: url,
- method: 'get',
- responseType: 'blob',
- params: query,
- }).then((response) => {
- handleBlobFile(response, fileName);
- });
- }
- /**
- * blob 文件刘处理
- * @param response 响应结果
- * @returns
- */
- export function handleBlobFile(response: any, fileName: string) {
- // 处理返回的文件流
- const blob = response;
- if (blob && blob.size === 0) {
- useMessage().error('内容为空,无法下载');
- return;
- }
- const link = document.createElement('a');
- // 兼容一下 入参不是 File Blob 类型情况
- var binaryData = [] as any;
- binaryData.push(response);
- link.href = window.URL.createObjectURL(new Blob(binaryData));
- link.download = fileName;
- document.body.appendChild(link);
- link.click();
- window.setTimeout(function () {
- // @ts-ignore
- URL.revokeObjectURL(blob);
- document.body.removeChild(link);
- }, 0);
- }
- /**
- * @description 生成唯一 uuid
- * @return string
- */
- export function generateUUID() {
- if (typeof crypto === 'object') {
- if (typeof crypto.randomUUID === 'function') {
- return crypto.randomUUID();
- }
- if (typeof crypto.getRandomValues === 'function' && typeof Uint8Array === 'function') {
- const callback = (c: any) => {
- const num = Number(c);
- return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(16);
- };
- return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, callback);
- }
- }
- let timestamp = new Date().getTime();
- let performanceNow = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0;
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
- let random = Math.random() * 16;
- if (timestamp > 0) {
- random = (timestamp + random) % 16 | 0;
- timestamp = Math.floor(timestamp / 16);
- } else {
- random = (performanceNow + random) % 16 | 0;
- performanceNow = Math.floor(performanceNow / 16);
- }
- return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16);
- });
- }
- /**
- * 统一批量导出
- * @method elSvg 导出全局注册 element plus svg 图标
- * @method useTitle 设置浏览器标题国际化
- * @method setTagsViewNameI18n 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
- * @method lazyImg 图片懒加载
- * @method globalComponentSize() element plus 全局组件大小
- * @method deepClone 对象深克隆
- * @method isMobile 判断是否是移动端
- * @method handleEmpty 判断数组对象中所有属性是否为空,为空则删除当前行对象
- * @method handleOpenLink 打开外部链接
- */
- const other = {
- elSvg: (app: App) => {
- elSvg(app);
- },
- useTitle: () => {
- useTitle();
- },
- setMenuI18n(item: RouteItems) {
- return setMenuI18n(item)
- },
- lazyImg: (el: string, arr: EmptyArrayType) => {
- lazyImg(el, arr);
- },
- globalComponentSize: () => {
- return globalComponentSize();
- },
- deepClone: (obj: EmptyObjectType) => {
- return deepClone(obj);
- },
- isMobile: () => {
- return isMobile();
- },
- handleEmpty: (list: EmptyArrayType) => {
- return handleEmpty(list);
- },
- handleOpenLink: (val: RouteItem) => {
- handleOpenLink(val);
- },
- encryption: (src: string) => {
- return encryption(src);
- },
- decryption: (src: string) => {
- return decryption(src);
- },
- base64Encrypt: (data: any) => {
- return base64Encrypt(data);
- },
- downBlobFile: (url: any, query: any, fileName: string) => {
- return downBlobFile(url, query, fileName);
- },
- toUnderline: (str: string) => {
- return toUnderline(str);
- },
- openWindow: (url: string, title: string, w: number, h: number) => {
- return openWindow(url, title, w, h);
- },
- getQueryString: (url: string, paraName: string) => {
- return getQueryString(url, paraName);
- },
- adaptationUrl: (url?: string) => {
- return adaptationUrl(url);
- },
- resolveAllEunuchNodeId: (json: any[], idArr: any[], temp: any[] = []) => {
- return resolveAllEunuchNodeId(json, idArr, temp);
- },
- getNonDuplicateID: () => {
- return getNonDuplicateID();
- },
- addUnit: (value: string | number, unit = 'px') => {
- return addUnit(value, unit);
- },
- };
- export function getQueryString(url: string, paraName: string) {
- const arrObj = url.split('?');
- if (arrObj.length > 1) {
- const arrPara = arrObj[1].split('&');
- let arr;
- for (let i = 0; i < arrPara.length; i++) {
- arr = arrPara[i].split('=');
- // eslint-disable-next-line eqeqeq
- if (arr != null && arr[0] == paraName) {
- return arr[1];
- }
- }
- return '';
- } else {
- return '';
- }
- }
- /**
- * 列表结构转树结构
- * @param data
- * @param id
- * @param parentId
- * @param children
- * @param rootId
- * @returns {*}
- */
- export function handleTree(data: any, id: any, parentId: any, children: any, rootId: any) {
- id = id || 'id';
- parentId = parentId || 'parentId';
- children = children || 'children';
- rootId =
- rootId ||
- Math.min.apply(
- Math,
- data.map((item: any) => {
- return item[parentId];
- })
- ) ||
- 0;
- //对源数据深度克隆
- const cloneData = JSON.parse(JSON.stringify(data));
- //循环所有项
- const treeData = cloneData.filter((father: any) => {
- const branchArr = cloneData.filter((child: any) => {
- //返回每一项的子级数组
- return father[id] === child[parentId];
- });
- branchArr.length > 0 ? (father[children] = branchArr) : '';
- //返回第一层
- return father[parentId] === rootId;
- });
- return treeData !== '' ? treeData : data;
- }
- /**
- * 解析所有太监节点ID
- * @returns
- */
- const resolveAllEunuchNodeId = (json: any[], idArr: any[], temp: any[] = []) => {
- for (const item of json) {
- if (item.children && item.children.length !== 0) {
- resolveAllEunuchNodeId(item.children, idArr, temp);
- } else {
- temp.push(...idArr.filter((id) => id === item.id));
- }
- }
- return temp;
- };
- /**
- *
- * @param str 驼峰转下划线
- * @returns 下划线
- */
- export function toUnderline(str: string) {
- return str.replace(/([A-Z])/g, '_$1').toLowerCase();
- }
- /**
- * 自动适配不同的后端架构
- * 1. 例如 /act/oa/task ,在微服务架构保持不变,在单体架构编程 /admin/oa/task
- * 2. 特殊 /gen/xxx ,在微服务架构、单体架构编程 都需保持不变
- *
- * @param originUrl 原始路径
- */
- const adaptationUrl = (originUrl?: string) => {
- // 微服务架构 不做路径转换,为空不做路径转换
- const isMicro = import.meta.env.VITE_IS_MICRO;
- if (validateNull(isMicro) || isMicro === 'true') {
- return originUrl;
- }
- // 验证码服务
- if (originUrl?.startsWith('/code/')) {
- return `/admin${originUrl}`;
- }
- // 如果是代码生成服务,不做路径转换
- if (originUrl?.startsWith('/gen')) {
- return originUrl;
- }
- // 转为 /admin 路由前缀的请求
- return `/admin/${originUrl?.split('/').splice(2).join('/')}`;
- };
- /**
- * @description 获取不重复的id
- * @param length { Number } id的长度
- * @return { String } id
- */
- const getNonDuplicateID = (length = 8) => {
- let idStr = Date.now().toString(36);
- idStr += Math.random().toString(36).substring(3, length);
- return idStr;
- };
- /**
- * @description 添加单位
- * @param {String | Number} value 值 100
- * @param {String} unit 单位 px em rem
- */
- const addUnit = (value: string | number, unit = 'px') => {
- return !Object.is(Number(value), NaN) ? `${value}${unit}` : value;
- };
- // 统一批量导出
- export default other;
|