# 工具函数 :::tip 说明 前端工具函数位于 `src/utils/` 目录,提供认证管理、本地存储、日期格式化、树结构操作、文件下载等通用能力。 ::: ## auth.ts 认证与通用工具函数,位于 `src/utils/auth.ts`: ```typescript // 外部链接判断 export function isExternal(path: string) { return /^(https?:|mailto:|tel:)/.test(path); } // 路径规范化 export function getNormalPath(path: string) { if (path.length === 0 || !path || path == 'undefined') return path; const newPath = path.replace('//', '/'); return newPath[newPath.length - 1] === '/' ? newPath.slice(0, -1) : newPath; } // 确认弹窗封装(使用 Ant Design Vue 的 Modal.confirm) export function confirm(msg: string) { return new Promise((resolve, reject) => { Modal.confirm({ title: '温馨提示', content: msg, onOk: resolve, onCancel: reject, }); }); } // 消息提示封装(使用 Ant Design Vue 的 message) export function showMsg(msg: string, type = 'success') { message[type](msg); } // 文件流下载 export function streamFileDownload(file: any, fileName = '文件名称.zip') { const blob = new Blob([file], { type: 'application/octet-stream;charset=UTF-8' }); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.setAttribute('download', fileName); document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); } ``` ### 树结构操作 `auth.ts` 中还包含树结构转换工具: ```typescript // 数组转树 export const arrayToTree = ( data: any[], props = { id: 'id', parentId: 'pid', children: 'children' }, ) => { data = cloneDeep(data); const { id, parentId, children } = props; const result: any[] = []; const map = new Map(); data.forEach((item) => { map.set(item[id], item); const parent = map.get(item[parentId]); if (parent) { parent[children] = parent[children] ?? []; parent[children].push(item); } else { result.push(item); } }); return result; }; // 树转数组(广度优先) export const treeToArray = (data: any[], props = { children: 'children' }) => { data = cloneDeep(data); const newData = []; const queue: any[] = []; data.forEach((child) => queue.push(child)); while (queue.length) { const item = queue.shift(); if (item[children]) { item[children].forEach((child) => queue.push(child)); delete item[children]; } newData.push(item); } return newData; }; // 递归查找路径 export const findTreeByPath = (tree, path, result = []) => { for (const node of tree) { if (node.path === path) result.push(node); if (node.children?.length) findTreeByPath(node.children, path, result); } return result; }; ``` ## Storage.ts 本地存储封装,支持过期时间和 cookie,位于 `src/utils/Storage.ts`: ```typescript const DEFAULT_CACHE_TIME = 7 * 24 * 60 * 60 * 1000; // 7 天 export const createStorage = ({ prefixKey = '', storage = localStorage } = {}) => { const Storage = class { private storage = storage; private prefixKey?: string = prefixKey; private getKey(key: string) { return `${this.prefixKey}${key}`.toUpperCase(); // 自动大写 } // 设置缓存(支持过期时间) set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) { const stringData = JSON.stringify({ value, expire: expire !== null ? Date.now() + expire : null, }); this.storage.setItem(this.getKey(key), stringData); } // 读取缓存(过期自动删除) get(key: string, def: any = null) { const item = this.storage.getItem(this.getKey(key)); if (item) { try { const data = JSON.parse(item); const { value, expire } = data; if (expire === null || expire >= Date.now()) return value; this.remove(key); // 过期删除 } catch (e) { return def; } } return def; } remove(key: string) { this.storage.removeItem(this.getKey(key)); } clear(): void { this.storage.clear(); } }; return new Storage(); }; export const storage = createStorage(); ``` Store mutation-types 定义了存储键名: ```typescript // src/store/mutation-types.ts export const ACCESS_TOKEN = 'ACCESS-TOKEN'; // 用户 token export const CURRENT_USER = 'CURRENT-USER'; // 当前用户信息 export const IS_LOCKSCREEN = 'IS-LOCKSCREEN'; // 是否锁屏 export const TABS_ROUTES = 'TABS-ROUTES'; // 标签页 export const FIRST_ROUTE = 'FIRST-ROUTE'; // 菜单第一个路由 ``` ## dateUtil.ts 日期格式化工具,基于 dayjs,位于 `src/utils/dateUtil.ts`: ```typescript import dayjs from 'dayjs'; const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm'; const DATE_FORMAT = 'YYYY-MM-DD '; export function formatToDateTime(date: Date, formatStr = DATE_TIME_FORMAT): string { return dayjs(date).format(formatStr); } export function formatToDate(date: Date, formatStr = DATE_FORMAT): string { return dayjs(date).format(formatStr); } ``` `dateUtil` 也被 `vite.config.ts` 使用,记录构建时间戳: ```typescript // vite.config.ts import { formatToDateTime } from './src/utils/dateUtil'; const __APP_INFO__ = { pkg: { dependencies, devDependencies, name, version }, lastBuildTime: formatToDateTime(new Date()), }; ``` ## httpEnum.ts HTTP 相关枚举定义,位于 `src/enums/httpEnum.ts`: ```typescript export enum ResultEnum { SUCCESS = 0, // 业务成功 ERROR = 1, // 业务失败 TIMEOUT = 401, // 登录超时 } export enum RequestEnum { GET = 'GET', POST = 'POST', PUT = 'PUT', DELETE = 'DELETE', } export enum ContentTypeEnum { JSON = 'application/json;charset=UTF-8', FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', FORM_DATA = 'multipart/form-data;charset=UTF-8', } ``` ## pageEnum.ts 页面路径枚举,位于 `src/enums/pageEnum.ts`: ```typescript export enum PageEnum { BASE_LOGIN = '/login', BASE_LOGIN_NAME = 'Login', REDIRECT = '/redirect', BASE_HOME = '/dashboard', BASE_HOME_REDIRECT = '/dashboard/console', ERROR_PAGE_NAME = 'ErrorPage', } ``` :::tip 温馨提示 `Storage` 工具类自动将键名转为大写(如 `access-token` → `ACCESS-TOKEN`),存储时包含过期时间,读取时自动检查是否过期。`auth.ts` 中的 `confirm` 和 `message` 函数是对 Ant Design Vue 的简封装,在业务组件中直接调用即可。 ::: ## 总结 工具函数库提供了 Storage(本地存储,支持过期)、auth(认证管理、树结构操作、文件下载)、dateUtil(日期格式化)、httpEnum/pageEnum(枚举定义)等通用能力。`confirm` 和 `message` 是 Ant Design Vue 的简封装,`arrayToTree`/`treeToArray` 处理菜单数据转换。