工具类
3.0 中全局辅助函数拆分为 src/utils(纯工具)与 src/helpers(依赖 store 的业务辅助)两处,以下为常用工具速览
AppInit
认证通过后加载系统所需的各种数据,位于
src/app-init.ts
const initApp = async (): Promise<void>初始化应用:用户信息 → 服务端主题(唯一事实源,亮暗档位除外)→ 动态路由 → 菜单 → viewTabs,设置最近使用缓存 key,恢复上次打开标签,清除字典 store 与组件缓存
import {initApp} from "@/app-init.ts"; await initApp()const refreshApp = async (route: RouteLocationNormalizedLoaded)刷新应用(数据更新):调用后端
reloadData后重新initApp,重新生成内容区组件 key,校验当前菜单权限后重载 ViewTab 或跳回首页import {refreshApp} from "@/app-init.ts"; await refreshApp(route)
Auth
判断用户是否拥有某些角色,位于
src/helpers/auth.ts
const hasRouteRole = (routeRoleList?: string[]): boolean判断用户是否拥有指定角色,传入角色编码集合,当角色有任意一个角色存在时即返回 true;不配置或配置为空数组则所有用户可访问
import {hasRouteRole} from "@/helpers/auth.ts"; const hasTargetRole:boolean = hasRouteRole(["ROLE_admin"])const isAdmin = (): boolean判断当前登录角色是否为超级管理员
import {isAdmin} from "@/helpers/auth.ts"; const admin = isAdmin()
Browser
获取浏览器类型及版本,当前浏览器不完全兼容或版本过低时进行提示时使用,位于
src/utils/browser.ts
export const getBrowserType = (): string获取浏览器类型
import {getBrowserType} from "@/utils/browser.ts" const browserType = getBrowserType()export const getBrowserMajorVersion = (): number获取浏览器主要版本号
import {getBrowserMajorVersion} from "@/utils/browser.ts" const browserMajorVersion = getBrowserMajorVersion()
BrowserId
获取浏览器指纹id(基于 @fingerprintjs/fingerprintjs),该id与用户浏览器软件和机器硬件相关,同一浏览器id值一般唯一,系统中用于作为 WebSocket 连接的 clientId
const createBrowserId = async (): Promise<string>获取当前浏览器id
import {createBrowserId} from "@/utils/browser-id.ts"; const browserId = await createBrowserId()
Crypto
用于系统前端的数据加解密(AES-CBC,crypto-js)。Key/IV 硬编码于前端源码,仅作「记住我」密码与锁屏密码的本地混淆(防肩窥),不是真正的保密手段,勿用于新的保密场景
const encrypt = (data: string): string数据加密
import {encrypt} from "@/utils/crypto.ts" const encrypted = encrypt("data")const decrypt = (data: string): string数据解密
import {decrypt} from "@/utils/crypto.ts" const data = decrypt(encrypted)
Dict
系统字典,位于
src/helpers/dict.ts
const initDict = (...dictTypeCodes: string[]): Record<string, ComputedRef<SysDictDataType[]>>通过字典编码获取字典options,缺失编码合并为一次批量请求并进行并发去重,详细用法见:系统字典
const getDictLabel = (option: SysDictDataType[], value?: string): string | undefined通过字典options和value获取label
import {getDictLabel} from "@/helpers/dict.ts"; const label = getDictLabel(sys_notice_type.value, type)const reLoadDict = (code: string): Promise<void>通过字典编码重新从后端拉取字典并更新 store(消费页经 computed 即时更新)
import {reLoadDict} from "@/helpers/dict.ts"; await reLoadDict(dictTypeCode)
AttachmentDownload
附件下载工具类,位于
src/utils/attachment-download.ts
export const download = (data: string | Blob, fileName?: string)通用下载,根据传入参数不同自动调用不同的下载函数(Blob 走对象URL,字符串按链接处理)
import {download} from "@/utils/attachment-download.ts"; // 传入 blob 或 url。附件名称选填 download(blob, file.name)const downloadBlob = (blob: Blob, filename?: string)下载blob附件(对象URL延迟60s释放,避免引用泄漏)
import {downloadBlob} from "@/utils/attachment-download.ts"; downloadBlob(blob, fileName)const downloadFromUrl = (url: string, fileName?: string)通过URL进行附件下载
import {downloadFromUrl} from "@/utils/attachment-download.ts"; downloadFromUrl(url, fileName);
HandleDate
特殊的日期格式处理,位于
src/utils/handle-date.ts
const handleTime = (time: string): string传入
YYYY-MM-DD HH:mm格式的日期字符串,格式化为今天昨天前天类型的日期形式import dayjs from "dayjs"; import {handleTime} from "@/utils/handle-date.ts"; // 调用dayjs格式化item.releaseTime的日期格式,通过handleTime 进行再次处理 handleTime(dayjs(item.releaseTime).format('YYYY-MM-DD HH:mm'))
Os
获取操作系统类型,位于
src/utils/os.ts
const osType = (): 'Windows' | 'MacOS' | 'Linux' | 'Android' | 'iOS' | 'Unknown'获取当前操作系统类型
import {osType} from "@/utils/os.ts"; const type = osType()
Request
axios 请求、响应拦截器及数据返回统一样式的封装,位于
src/utils/request.ts,详见Api
请求拦截器:为axios请求的请求头添加
Authorization: Bearer <token>与Client-Type: web响应拦截器:对于后端返回的特殊业务码进行处理(401:token失效,5 秒单飞窗清空用户数据后跳回登录页;451:非法ip访问,跳转到451页面),错误提示 3 秒去重,所有异常统一抛出
ResponseError(code, msg)export default async function request<T> (config: AxiosRequestConfig): Promise<ResponseType<T>>axios请求返回统一样式的封装,由api接口进行调用,通过传入泛型可在组件中推断出数据类型
import request from "@/utils/request.ts"; // 通过传入泛型可在组件中推断出数据类型 export const findList = (data: SysDictDataType) => { return request<Array<SysDictDataType>>({ url: 'system/dictData/list', method: 'post', data: data }) }export const blobRequest = async (config: AxiosRequestConfig): Promise<Blob>二进制类型请求,responseType 固定为 blob,直接返回 Blob,用于附件下载等场景
import {blobRequest} from "@/utils/request.ts"; const blob = await blobRequest({url: 'system/attachment/download/' + id, method: 'get'})
Scrollbar
页面滚动条控制(基于 overlayscrollbars 的页面级悬浮滚动条 + 滚动锁),位于
src/utils/scrollbar.ts
const initPageScrollbar = (): OverlayScrollbars | undefined页面级悬浮滚动条接管(幂等,可在任意挂载点重复调用;移动端浏览器跳过接管恢复原生滚动)
import {initPageScrollbar} from "@/utils/scrollbar.ts"; initPageScrollbar()const hiddenOverflowY():void锁定页面滚动(蒙层/锁屏等显式调用;幂等)
import {hiddenOverflowY} from "@/utils/scrollbar.ts"; hiddenOverflowY()const showOverflowY(): void恢复页面滚动
import {showOverflowY} from "@/utils/scrollbar.ts"; showOverflowY()const bridgeAntdScrollLock = (): voidantd 弹层(Modal/Drawer/图片预览)打开时的滚动锁镜像桥接,应用启动时调用一次
import {bridgeAntdScrollLock} from "@/utils/scrollbar.ts"; bridgeAntdScrollLock()
Token
处理登录令牌,位于
src/helpers/token.ts。token 持久化在localStorage['lihua_token'](经 @vueuse useStorage 响应式管理)
const getToken = ():string获取登录token
import token from "@/helpers/token.ts" token.getToken()const setToken = (token: string):void设置用户token
import token from "@/helpers/token.ts"; token.setToken(data)const removeToken = ()删除用户token
import token from "@/helpers/token.ts"; token.removeToken()
Tree
前端进行树形结构的构建和对树形结构进行扁平化处理,位于
src/utils/tree.ts
export const buildTree = <T> (originList: Array<T>, rootValue?, id?, parentId?, children?)构建树形结构传入扁平化的具有树形结构元素的集合,返回构建完成的树形结构。
import {buildTree} from "@/utils/tree.ts"; const treeList = buildTree(resp.data); // 打印出树形结构的Array集合 console.log(treeList)为兼容各种数据结构,可通过参数指定各个属性的字段名
import {buildTree} from "@/utils/tree.ts"; // 通过参数指定root节点值、id属性名、pid属性名、子节点属性名 const treeList = buildTree(resp.data,"0","code","pCode","children"); // 打印出树形结构的Array集合 console.log(treeList)export const flattenTree = <T> (tree:Array<T>, children: string = 'children')扁平化树形结构传入树形结构集合,执行完成后返回Array集合
import {flattenTree} from "@/utils/tree.ts"; const flattenDeptList = flattenTree(resp.data) // 打印出没有树形结构的Array集合 console.log(flattenDeptList)const traverse = <T> (tree: Array<T>, callback: (item: T) => void | boolean, children: string = 'children')遍历树形结构,参数一传入树形结构数组。参数二为回调函数,返回的item为遍历出的每个节点对象,回调 return true 可终止递归。参数三为children对应的节点名称,默认children
import { traverse } from "@/utils/tree.ts"; // 树形结构 const treeList = [{ id: '1', data: 'xxx', children: [{ id: '1-1', data: 'xxx', children: [{}] }] }] // 调用递归遍历 traverse(treeList, (item) => { // 每个节点的数据 console.log(item) }, 'children')const traverseWithPath = <T> (tree: T[], callback: (path: T[]) => any, children: string = 'children')带路径遍历树形结构,回调参数为从根到当前节点的完整路径数组,回调返回值收集成数组返回
import { traverseWithPath } from "@/utils/tree.ts"; traverseWithPath(treeList, (path) => { // path 为从根到当前节点的完整路径 console.log(path) })
WebSocket
WebSocket 单例管理器,位于
src/utils/web-socket.ts,详见websocket
const connect = async (): Promise<void>连接 WebSocket(先取一次性令牌再建立连接),登录后由路由守卫自动调用
import {connect} from "@/utils/web-socket.ts"; await connect()const addEventListener = (type: string, callback: (data: any) => void)添加监听订阅,消息类型需与后台定义相同
import {addEventListener} from "@/utils/web-socket.ts"; addEventListener("WS_NOTICE", (data) => {console.log(data)})const sendMessage = (type: string, data: any): boolean发送数据(以
{type, data, timestamp}协议封装),连接未就绪返回 falseimport {sendMessage} from "@/utils/web-socket.ts"; sendMessage("WS_TYPE", data)
WindowGuard
按键时间窗守卫(前沿节流),位于
src/utils/window-guard.ts。同一 key 在窗口期内只有第一次放行,其后拒直到窗口过期;窗口按时间流逝自动复位。典型用途:并发请求失败时同文案 message 只弹一条、认证失效联动只执行一次
const createWindowGuard = (windowMs: number): (key: string) => boolean创建指定窗口时长(ms)的守卫函数,返回的函数传入 key,返回本次是否放行
import {createWindowGuard} from "@/utils/window-guard.ts"; const guard = createWindowGuard(3000) // 同一 key 3 秒内只放行一次 if (guard('error-notify')) { message.error(msg) }

