Skip to content

Commit

Permalink
refactor: http util and route store (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
ppxb authored Jan 4, 2025
1 parent aa14d6b commit d3aeca8
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 172 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"@antfu/eslint-config": "^2.16.3",
"@arco-design/web-vue": "^2.56.0",
"@types/crypto-js": "^4.2.2",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.2.5",
"@types/query-string": "^6.3.0",
"@vitejs/plugin-vue": "^5.0.4",
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions src/router/asyncModules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type ImportVueFileType = typeof import('*.vue')
type ImportVueFileFnType = () => Promise<ImportVueFileType>

const moduleFiles = import.meta.glob<ImportVueFileType>('@/views/**/*.vue')

export const asyncRouteModules = Object.entries(moduleFiles).reduce((routes, [url, importFn]) => {
if (!/\/(views\/login|components)\//.test(url)) {
const path = url.replace('/src/views/', '').replace('.vue', '')
routes[path] = importFn
}

return routes
}, {} as Recordable<ImportVueFileFnType>)
43 changes: 14 additions & 29 deletions src/stores/modules/dict.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,36 @@
import { defineStore } from 'pinia'
import type { DictState, LabelValueState } from '@/types/global'
import type { LabelValueState } from '@/types/global'

const storeSetup = () => {
const dictData = ref<DictState[]>([])
const dictData = ref(new Map<string, LabelValueState[]>())

// 设置字典
const setDict = (_code: string, items: Array<LabelValueState>) => {
if (_code !== null && _code !== '') {
dictData.value.push({
code: _code,
items,
})
const setDict = (code: string, items: Array<LabelValueState>) => {
if (code) {
dictData.value.set(code, items)
}
}

// 获取字典
const getDict = (_code: string) => {
if (_code == null || _code === '') {
return null
}
for (let i = 0; i < dictData.value.length; i += 1) {
if (dictData.value[i].code === _code) {
return dictData.value[i].items
}
}
return null
const getDict = (code: string) => {
if (!code) return null
return dictData.value.get(code) || null
}

// 删除字典
const deleteDict = (_code: string) => {
let bln = false
const deleteDict = (code: string) => {
try {
for (let i = 0; i < dictData.value.length; i += 1) {
if (dictData.value[i].code === _code) {
dictData.value.splice(i, 1)
return true
}
}
return dictData.value.delete(code)
} catch (e) {
bln = false
return false
}
return bln
}

// 清空字典
const cleanDict = () => {
dictData.value = []
dictData.value.clear()
}

return {
setDict,
getDict,
Expand Down
77 changes: 26 additions & 51 deletions src/stores/modules/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,18 @@ import type { RouteRecordRaw } from 'vue-router'
import { mapTree, toTreeArray } from 'xe-utils'
import { cloneDeep, omit } from 'lodash-es'
import { constantRoutes, systemRoutes } from '@/router/route'
import ParentView from '@/components/ParentView/index.vue'
import { type RouteItem, getUserRoute } from '@/apis'
import { transformPathToName } from '@/utils'
import { asyncRouteModules } from '@/router/asyncModules'

const Layout = () => import('@/layout/index.vue')

// 匹配views里面所有的.vue文件
const modules = import.meta.glob('@/views/**/*.vue')

/** 加载模块 */
export const loadView = (view: string) => {
let res
for (const path in modules) {
const dir = path.split('views/')[1].split('.vue')[0]
if (dir === view) {
res = () => modules[path]()
}
}
return res
const layoutComponentMap = {
Layout: () => import('@/layout/index.vue'),
ParentView: () => import('@/components/ParentView/index.vue'),
}

/** 将component由字符串转成真正的模块 */
const transformComponentView = (component: string) => {
if (component === 'Layout') {
return Layout as never
} else if (component === 'ParentView') {
return ParentView as never
} else {
return loadView(component) as never
}
return layoutComponentMap[component as keyof typeof layoutComponentMap] || asyncRouteModules[component]
}

/**
Expand All @@ -44,16 +26,20 @@ const transformComponentView = (component: string) => {
*/
const formatAsyncRoutes = (menus: RouteItem[]) => {
if (!menus.length) return []

const pathMap = new Map()
const routes = mapTree(menus, (item) => {
return mapTree(menus, (item) => {
pathMap.set(item.id, item.path)
if (item.children && item.children.length) {
item.children.sort((a, b) => (a?.sort ?? 0) - (b?.sort ?? 0)) // 排序

if (item.children?.length) {
item.children.sort((a, b) => (a?.sort ?? 0) - (b?.sort ?? 0))
}

// 部分子菜单,例如:通知公告新增、查看详情,需要选中其父菜单
if (item.parentId && item.type === 2 && item.permission) {
item.activeMenu = pathMap.get(item.parentId)
}

return {
path: item.path,
name: item.name ?? transformPathToName(item.path),
Expand All @@ -68,30 +54,24 @@ const formatAsyncRoutes = (menus: RouteItem[]) => {
activeMenu: item.activeMenu,
},
}
})
return routes as RouteRecordRaw[]
}) as unknown as RouteRecordRaw[]
}

/** 判断路由层级是否大于 2 */
export const isMultipleRoute = (route: RouteRecordRaw) => {
const children = route.children
if (children?.length) {
// 只要有一个子路由的 children 长度大于 0,就说明是三级及其以上路由
return children.some((child) => child.children?.length)
}
return false
return route.children?.some((child) => child.children?.length) ?? false
}

/** 路由降级(把三级及其以上的路由转化为二级路由) */
export const flatMultiLevelRoutes = (routes: RouteRecordRaw[]) => {
const cloneRoutes = cloneDeep(routes)
cloneRoutes.forEach((route) => {
if (isMultipleRoute(route)) {
const flatRoutes = toTreeArray(route.children)
route.children = flatRoutes.map((i) => omit(i, 'children')) as RouteRecordRaw[]
return cloneDeep(routes).map((route) => {
if (!isMultipleRoute(route)) return route

return {
...route,
children: toTreeArray(route.children).map((item) => omit(item, 'children')) as RouteRecordRaw[],
}
})
return cloneRoutes
}

const storeSetup = () => {
Expand All @@ -109,17 +89,12 @@ const storeSetup = () => {
}

// 生成路由
const generateRoutes = (): Promise<RouteRecordRaw[]> => {
return new Promise((resolve) => {
// 向后端请求路由数据 这个接口已经根据用户角色过滤了没权限的路由(后端根据用户角色过滤路由显得比较安全些)
getUserRoute().then((res) => {
const asyncRoutes = formatAsyncRoutes(res.data)
setRoutes(asyncRoutes)
const cloneRoutes = cloneDeep(asyncRoutes)
const flatRoutes = flatMultiLevelRoutes(cloneRoutes as RouteRecordRaw[])
resolve(flatRoutes)
})
})
const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
const { data } = await getUserRoute()
const asyncRoutes = formatAsyncRoutes(data)
const flatRoutes = flatMultiLevelRoutes(cloneDeep(asyncRoutes))
setRoutes(asyncRoutes)
return flatRoutes
}

return {
Expand Down
6 changes: 2 additions & 4 deletions src/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ export interface LabelValueState {
extra?: string
}

/** 字典类型 */
export interface DictState {
code: string
items: Array<LabelValueState>
declare global{
type Recordable<T = any> = Record<string, T>
}

/** 状态(1:启用;2:禁用) */
Expand Down
Loading

0 comments on commit d3aeca8

Please sign in to comment.