Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
najiu-admin-template
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
najiu-frontend
najiu-admin-template
Commits
e12c588c
Commit
e12c588c
authored
Mar 17, 2021
by
Vben
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor(route): refactoring the routing multi-layer model close #215
parent
37320160
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
275 additions
and
345 deletions
+275
-345
.eslintrc.js
.eslintrc.js
+4
-4
settings.json
.vscode/settings.json
+0
-1
CHANGELOG.zh_CN.md
CHANGELOG.zh_CN.md
+6
-0
hmr.ts
build/vite/plugin/hmr.ts
+21
-0
index.ts
build/vite/plugin/index.ts
+4
-0
Breadcrumb.vue
src/layouts/default/header/components/Breadcrumb.vue
+2
-1
ParentView.vue
src/layouts/page/ParentView.vue
+0
-63
index.vue
src/layouts/page/index.vue
+15
-5
useCache.ts
src/layouts/page/useCache.ts
+0
-63
tabChange.ts
src/logics/mitt/tabChange.ts
+2
-2
constant.ts
src/router/constant.ts
+14
-71
permissionGuard.ts
src/router/guard/permissionGuard.ts
+1
-1
menuHelper.ts
src/router/helper/menuHelper.ts
+18
-29
routeHelper.ts
src/router/helper/routeHelper.ts
+71
-29
index.ts
src/router/menus/index.ts
+4
-12
basic.ts
src/router/routes/basic.ts
+67
-0
index.ts
src/router/routes/index.ts
+5
-1
permission.ts
src/store/modules/permission.ts
+4
-3
tab.ts
src/store/modules/tab.ts
+19
-56
index.ts
src/utils/index.ts
+17
-3
vite.config.ts
vite.config.ts
+1
-1
No files found.
.eslintrc.js
View file @
e12c588c
...
...
@@ -38,15 +38,15 @@ module.exports = {
'
@typescript-eslint/no-unused-vars
'
:
[
'
error
'
,
{
argsIgnorePattern
:
'
^
h$
'
,
varsIgnorePattern
:
'
^
h$
'
,
argsIgnorePattern
:
'
^
_
'
,
varsIgnorePattern
:
'
^
_
'
,
},
],
'
no-unused-vars
'
:
[
'
error
'
,
{
argsIgnorePattern
:
'
^
h$
'
,
varsIgnorePattern
:
'
^
h$
'
,
argsIgnorePattern
:
'
^
_
'
,
varsIgnorePattern
:
'
^
_
'
,
},
],
'
space-before-function-paren
'
:
'
off
'
,
...
...
.vscode/settings.json
View file @
e12c588c
...
...
@@ -8,7 +8,6 @@
"explorer.openEditors.visible"
:
0
,
"editor.tabSize"
:
2
,
"editor.renderControlCharacters"
:
true
,
"window.zoomLevel"
:
-1
,
"editor.minimap.renderCharacters"
:
false
,
"editor.minimap.maxColumn"
:
300
,
"editor.minimap.showSlider"
:
"always"
,
...
...
CHANGELOG.zh_CN.md
View file @
e12c588c
## Wip
### ✨ Refactor
-
重构路由多层模式,解决嵌套 keepalive 执行多次问题
## 2.1.0 (2021-03-15)
### ✨ Features
...
...
build/vite/plugin/hmr.ts
0 → 100644
View file @
e12c588c
import
type
{
Plugin
}
from
'
vite
'
;
/**
* TODO
* Temporarily solve the Vite circular dependency problem, and wait for a better solution to fix it later. I don't know what problems this writing will bring.
* @returns
*/
export
function
configHmrPlugin
():
Plugin
{
return
{
name
:
'
singleHMR
'
,
handleHotUpdate
({
modules
,
file
})
{
if
(
file
.
match
(
/xml$/
))
return
[];
modules
.
forEach
((
m
)
=>
{
m
.
importedModules
=
new
Set
();
m
.
importers
=
new
Set
();
});
return
modules
;
},
};
}
build/vite/plugin/index.ts
View file @
e12c588c
...
...
@@ -17,6 +17,7 @@ import { configThemePlugin } from './theme';
import
{
configImageminPlugin
}
from
'
./imagemin
'
;
import
{
configWindiCssPlugin
}
from
'
./windicss
'
;
import
{
configSvgIconsPlugin
}
from
'
./svgSprite
'
;
import
{
configHmrPlugin
}
from
'
./hmr
'
;
export
function
createVitePlugins
(
viteEnv
:
ViteEnv
,
isBuild
:
boolean
)
{
const
{
VITE_USE_IMAGEMIN
,
VITE_USE_MOCK
,
VITE_LEGACY
,
VITE_BUILD_COMPRESS
}
=
viteEnv
;
...
...
@@ -28,6 +29,9 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
vueJsx
(),
];
// TODO
!
isBuild
&&
vitePlugins
.
push
(
configHmrPlugin
());
// @vitejs/plugin-legacy
VITE_LEGACY
&&
isBuild
&&
vitePlugins
.
push
(
legacy
());
...
...
src/layouts/default/header/components/Breadcrumb.vue
View file @
e12c588c
...
...
@@ -33,6 +33,7 @@
import
{
useGo
}
from
'
/@/hooks/web/usePage
'
;
import
{
isString
}
from
'
/@/utils/is
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
getMenus
}
from
'
/@/router/menus
'
;
export
default
defineComponent
({
name
:
'
LayoutBreadcrumb
'
,
...
...
@@ -47,7 +48,7 @@
const
{
getShowBreadCrumbIcon
}
=
useRootSetting
();
const
{
t
}
=
useI18n
();
watchEffect
(()
=>
{
watchEffect
(
async
()
=>
{
if
(
currentRoute
.
value
.
name
===
REDIRECT_NAME
)
return
;
const
matched
=
currentRoute
.
value
?.
matched
;
...
...
src/layouts/page/ParentView.vue
deleted
100644 → 0
View file @
37320160
<!--
* @Description: The reason is that tsx will report warnings under multi-level nesting.
-->
<
template
>
<div>
<RouterView>
<template
#default
="
{ Component, route }">
<transition
:name=
"
getTransitionName(
{
route,
openCache: openCache,
enableTransition: getEnableTransition,
cacheTabs: getCaches,
def: getBasicTransition,
})
"
mode="out-in"
appear
>
<keep-alive
v-if=
"openCache"
:include=
"getCaches"
>
<component
:is=
"Component"
v-bind=
"getKey(Component, route)"
/>
</keep-alive>
<component
v-else
:is=
"Component"
v-bind=
"getKey(Component, route)"
/>
</transition>
</
template
>
</RouterView>
</div>
</template>
<
script
lang=
"ts"
>
import
{
computed
,
defineComponent
,
unref
}
from
'
vue
'
;
import
{
useRootSetting
}
from
'
/@/hooks/setting/useRootSetting
'
;
import
{
useMultipleTabSetting
}
from
'
/@/hooks/setting/useMultipleTabSetting
'
;
import
{
useTransitionSetting
}
from
'
/@/hooks/setting/useTransitionSetting
'
;
import
{
useCache
,
getKey
}
from
'
./useCache
'
;
import
{
getTransitionName
}
from
'
./transition
'
;
export
default
defineComponent
({
parentView
:
true
,
setup
()
{
const
{
getCaches
}
=
useCache
(
false
);
const
{
getShowMultipleTab
}
=
useMultipleTabSetting
();
const
{
getOpenKeepAlive
}
=
useRootSetting
();
const
{
getBasicTransition
,
getEnableTransition
}
=
useTransitionSetting
();
const
openCache
=
computed
(()
=>
unref
(
getOpenKeepAlive
)
&&
unref
(
getShowMultipleTab
));
return
{
getCaches
,
getBasicTransition
,
openCache
,
getEnableTransition
,
getTransitionName
,
getKey
,
};
},
});
</
script
>
src/layouts/page/index.vue
View file @
e12c588c
...
...
@@ -16,9 +16,9 @@
appear
>
<keep-alive
v-if=
"openCache"
:include=
"getCaches"
>
<component
:is=
"Component"
v-bind=
"getKey(Component, route)
"
/>
<component
:is=
"Component"
:key=
"route.fullPath
"
/>
</keep-alive>
<component
v-else
:is=
"Component"
v-bind=
"getKey(Component, route)
"
/>
<component
v-else
:is=
"Component"
:key=
"route.fullPath
"
/>
</transition>
</
template
>
</RouterView>
...
...
@@ -34,15 +34,15 @@
import
{
useRootSetting
}
from
'
/@/hooks/setting/useRootSetting
'
;
import
{
useTransitionSetting
}
from
'
/@/hooks/setting/useTransitionSetting
'
;
import
{
useCache
,
getKey
}
from
'
./useCache
'
;
import
{
useMultipleTabSetting
}
from
'
/@/hooks/setting/useMultipleTabSetting
'
;
import
{
getTransitionName
}
from
'
./transition
'
;
import
{
useStore
}
from
'
vuex
'
;
export
default
defineComponent
({
name
:
'
PageLayout
'
,
components
:
{
FrameLayout
},
setup
()
{
const
{
getCaches
}
=
useCache
(
true
);
const
{
getShowMultipleTab
}
=
useMultipleTabSetting
();
const
{
getOpenKeepAlive
,
getCanEmbedIFramePage
}
=
useRootSetting
();
...
...
@@ -51,6 +51,17 @@
const
openCache
=
computed
(()
=>
unref
(
getOpenKeepAlive
)
&&
unref
(
getShowMultipleTab
));
const
{
getters
}
=
useStore
();
const
getCaches
=
computed
(():
string
[]
=>
{
if
(
!
unref
(
getOpenKeepAlive
))
{
return
[];
}
// TODO The useStore is used here mainly to solve the problem of circular dependency hot update
const
cacheTabs
=
getters
[
'
app-tab/getCachedTabsState
'
];
return
cacheTabs
;
});
return
{
getTransitionName
,
openCache
,
...
...
@@ -58,7 +69,6 @@
getBasicTransition
,
getCaches
,
getCanEmbedIFramePage
,
getKey
,
};
},
});
...
...
src/layouts/page/useCache.ts
deleted
100644 → 0
View file @
37320160
import
type
{
FunctionalComponent
}
from
'
vue
'
;
import
type
{
RouteLocation
}
from
'
vue-router
'
;
import
{
computed
,
ref
,
unref
,
getCurrentInstance
}
from
'
vue
'
;
import
{
useRootSetting
}
from
'
/@/hooks/setting/useRootSetting
'
;
import
{
useRouter
}
from
'
vue-router
'
;
import
{
useStore
}
from
'
vuex
'
;
const
ParentLayoutName
=
'
ParentLayout
'
;
const
PAGE_LAYOUT_KEY
=
'
__PAGE_LAYOUT__
'
;
export
function
getKey
(
component
:
FunctionalComponent
&
{
type
:
Indexable
},
route
:
RouteLocation
)
{
return
!!
component
?.
type
.
parentView
?
{}
:
{
key
:
route
.
fullPath
};
}
export
function
useCache
(
isPage
:
boolean
)
{
const
{
getters
}
=
useStore
();
const
name
=
ref
(
''
);
const
{
currentRoute
}
=
useRouter
();
const
instance
=
getCurrentInstance
();
const
routeName
=
instance
?.
type
.
name
;
if
(
routeName
&&
!
[
ParentLayoutName
].
includes
(
routeName
))
{
name
.
value
=
routeName
;
}
else
{
const
matched
=
currentRoute
.
value
?.
matched
;
if
(
!
matched
)
{
return
;
}
const
len
=
matched
.
length
;
if
(
len
<
2
)
return
;
name
.
value
=
matched
[
len
-
2
].
name
as
string
;
}
const
{
getOpenKeepAlive
}
=
useRootSetting
();
const
getCaches
=
computed
(():
string
[]
=>
{
if
(
!
unref
(
getOpenKeepAlive
))
{
return
[];
}
const
cached
=
getters
[
'
app-tab/getCachedMapState
'
];
if
(
isPage
)
{
// page Layout
return
cached
.
get
(
PAGE_LAYOUT_KEY
)
||
[];
}
const
cacheSet
=
new
Set
<
string
>
();
cacheSet
.
add
(
unref
(
name
));
const
list
=
cached
.
get
(
unref
(
name
));
if
(
!
list
)
{
return
Array
.
from
(
cacheSet
);
}
list
.
forEach
((
item
)
=>
{
cacheSet
.
add
(
item
);
});
return
Array
.
from
(
cacheSet
);
});
return
{
getCaches
};
}
src/logics/mitt/tabChange.ts
View file @
e12c588c
...
...
@@ -4,7 +4,7 @@
import
Mitt
from
'
/@/utils/mitt
'
;
import
type
{
RouteLocationNormalized
}
from
'
vue-router
'
;
import
{
getR
oute
}
from
'
/@/router/helper/routeHelper
'
;
import
{
getR
awRoute
}
from
'
/@/utils
'
;
const
mitt
=
new
Mitt
();
...
...
@@ -13,7 +13,7 @@ const key = Symbol();
let
lastChangeTab
:
RouteLocationNormalized
;
export
function
setLastChangeTab
(
lastChangeRoute
:
RouteLocationNormalized
)
{
const
r
=
getRoute
(
lastChangeRoute
);
const
r
=
getR
awR
oute
(
lastChangeRoute
);
mitt
.
emit
(
key
,
r
);
lastChangeTab
=
r
;
}
...
...
src/router/constant.ts
View file @
e12c588c
import
type
{
AppRouteRecordRaw
}
from
'
/@/router/types
'
;
import
ParentLayout
from
'
/@/layouts/page/ParentView.vue
'
;
import
{
t
}
from
'
/@/hooks/web/useI18n
'
;
export
const
REDIRECT_NAME
=
'
Redirect
'
;
export
const
PARENT_LAYOUT_NAME
=
'
ParentLayout
'
;
export
const
EXCEPTION_COMPONENT
=
()
=>
import
(
'
../views/sys/exception/Exception.vue
'
);
/**
...
...
@@ -12,78 +10,23 @@ export const EXCEPTION_COMPONENT = () => import('../views/sys/exception/Exceptio
export
const
LAYOUT
=
()
=>
import
(
'
/@/layouts/default/index.vue
'
);
/**
* @description: pa
ge
-layout
* @description: pa
rent
-layout
*/
export
const
getParentLayout
=
(
name
:
string
)
=>
{
export
const
getParentLayout
=
(
_name
?
:
string
)
=>
{
return
()
=>
new
Promise
((
resolve
)
=>
{
resolve
({
...
ParentLayout
,
name
,
name
:
PARENT_LAYOUT_NAME
,
});
});
};
// 404 on a page
export
const
PAGE_NOT_FOUND_ROUTE
:
AppRouteRecordRaw
=
{
path
:
'
/:path(.*)*
'
,
name
:
'
ErrorPage
'
,
component
:
LAYOUT
,
meta
:
{
title
:
'
ErrorPage
'
,
hideBreadcrumb
:
true
,
},
children
:
[
{
path
:
'
/:path(.*)*
'
,
name
:
'
ErrorPage
'
,
component
:
EXCEPTION_COMPONENT
,
meta
:
{
title
:
'
ErrorPage
'
,
hideBreadcrumb
:
true
,
},
},
],
};
export
const
REDIRECT_ROUTE
:
AppRouteRecordRaw
=
{
path
:
'
/redirect
'
,
name
:
REDIRECT_NAME
,
component
:
LAYOUT
,
meta
:
{
title
:
REDIRECT_NAME
,
hideBreadcrumb
:
true
,
},
children
:
[
{
path
:
'
/redirect/:path(.*)
'
,
name
:
REDIRECT_NAME
,
component
:
()
=>
import
(
'
/@/views/sys/redirect/index.vue
'
),
meta
:
{
title
:
REDIRECT_NAME
,
hideBreadcrumb
:
true
,
},
},
],
};
export
const
ERROR_LOG_ROUTE
:
AppRouteRecordRaw
=
{
path
:
'
/error-log
'
,
name
:
'
errorLog
'
,
component
:
LAYOUT
,
meta
:
{
title
:
'
ErrorLog
'
,
hideBreadcrumb
:
true
,
},
children
:
[
{
path
:
'
list
'
,
name
:
'
errorLogList
'
,
component
:
()
=>
import
(
'
/@/views/sys/error-log/index.vue
'
),
meta
:
{
title
:
t
(
'
routes.basic.errorLogList
'
),
hideBreadcrumb
:
true
,
},
},
],
};
// export const getParentLayout = (name: string) => {
// return () =>
// new Promise((resolve) => {
// resolve({
// ...ParentLayout,
// name,
// });
// });
// };
src/router/guard/permissionGuard.ts
View file @
e12c588c
...
...
@@ -5,7 +5,7 @@ import { permissionStore } from '/@/store/modules/permission';
import
{
PageEnum
}
from
'
/@/enums/pageEnum
'
;
import
{
userStore
}
from
'
/@/store/modules/user
'
;
import
{
PAGE_NOT_FOUND_ROUTE
}
from
'
/@/router/
constant
'
;
import
{
PAGE_NOT_FOUND_ROUTE
}
from
'
/@/router/
routes/basic
'
;
const
LOGIN_PATH
=
PageEnum
.
BASE_LOGIN
;
...
...
src/router/helper/menuHelper.ts
View file @
e12c588c
import
{
AppRouteModule
}
from
'
/@/router/types
'
;
import
type
{
MenuModule
,
Menu
,
AppRouteRecordRaw
}
from
'
/@/router/types
'
;
import
{
findPath
,
forEach
,
treeMap
}
from
'
/@/utils/helper/treeHelper
'
;
import
{
findPath
,
treeMap
}
from
'
/@/utils/helper/treeHelper
'
;
import
{
cloneDeep
}
from
'
lodash-es
'
;
import
{
isUrl
}
from
'
/@/utils/is
'
;
export
function
getAllParentPath
(
treeData
:
any
[],
path
:
string
)
{
export
function
getAllParentPath
<
T
=
Recordable
>
(
treeData
:
T
[],
path
:
string
)
{
const
menuList
=
findPath
(
treeData
,
(
n
)
=>
n
.
path
===
path
)
as
Menu
[];
return
(
menuList
||
[]).
map
((
item
)
=>
item
.
path
);
}
// 拼接父级路径
function
joinParentPath
(
list
:
any
,
node
:
any
)
{
let
allPaths
=
getAllParentPath
(
list
,
node
.
path
);
allPaths
=
allPaths
.
slice
(
0
,
allPaths
.
length
-
1
);
let
parentPath
=
''
;
if
(
Array
.
isArray
(
allPaths
)
&&
allPaths
.
length
>=
2
)
{
parentPath
=
allPaths
[
allPaths
.
length
-
1
];
}
else
{
allPaths
.
forEach
((
p
)
=>
{
parentPath
+=
/^
\/
/
.
test
(
p
)
?
p
:
`/
${
p
}
`
;
});
function
joinParentPath
(
menus
:
Menu
[],
parentPath
=
''
)
{
for
(
let
index
=
0
;
index
<
menus
.
length
;
index
++
)
{
const
menu
=
menus
[
index
];
const
p
=
menu
.
path
.
startsWith
(
'
/
'
)
?
menu
.
path
:
`/
${
menu
.
path
}
`
;
const
parent
=
isUrl
(
menu
.
path
)
?
menu
.
path
:
`
${
parentPath
}${
p
}
`
;
menus
[
index
].
path
=
parent
;
if
(
menu
?.
children
?.
length
)
{
joinParentPath
(
menu
.
children
,
parent
);
}
}
node
.
path
=
`
${
/^
\
//.test(node.path) ? node.path : `${parentPath}/${node.path}`}`.replace(
/
\
/
\
//g,
'
/
'
);
return
node
;
}
//
解析菜单模块
//
Parsing the menu module
export
function
transformMenuModule
(
menuModule
:
MenuModule
):
Menu
{
const
{
menu
}
=
menuModule
;
const
menuList
=
[
menu
];
forEach
(
menuList
,
(
m
)
=>
{
!
isUrl
(
m
.
path
)
&&
joinParentPath
(
menuList
,
m
);
});
joinParentPath
(
menuList
);
return
menuList
[
0
];
}
...
...
@@ -54,17 +44,16 @@ export function transformRouteToMenu(routeModList: AppRouteModule[]) {
routeList
.
push
(
item
);
}
});
return
treeMap
(
routeList
,
{
const
list
=
treeMap
(
routeList
,
{
conversion
:
(
node
:
AppRouteRecordRaw
)
=>
{
const
{
meta
:
{
title
,
icon
,
hideMenu
=
false
}
=
{}
}
=
node
;
!
isUrl
(
node
.
path
)
&&
joinParentPath
(
routeList
,
node
);
const
{
meta
:
{
title
,
hideMenu
=
false
}
=
{}
}
=
node
;
return
{
...(
node
.
meta
||
{}),
name
:
title
,
icon
,
path
:
node
.
path
,
hideMenu
,
};
},
});
joinParentPath
(
list
);
return
list
;
}
src/router/helper/routeHelper.ts
View file @
e12c588c
import
type
{
AppRouteModule
,
AppRouteRecordRaw
}
from
'
/@/router/types
'
;
import
type
{
Route
LocationNormalized
,
RouteRecordNormalized
}
from
'
vue-router
'
;
import
type
{
Route
r
,
RouteRecordNormalized
}
from
'
vue-router
'
;
import
{
getParentLayout
,
LAYOUT
}
from
'
/@/router/constant
'
;
import
{
cloneDeep
}
from
'
lodash-es
'
;
import
{
warn
}
from
'
/@/utils/log
'
;
import
{
createRouter
,
createWebHashHistory
}
from
'
vue-router
'
;
export
type
LayoutMapKey
=
'
LAYOUT
'
;
const
LayoutMap
=
new
Map
<
LayoutMapKey
,
()
=>
Promise
<
typeof
import
(
'
*.vue
'
)
>>
();
let
dynamicViewsModules
:
Record
<
string
,
()
=>
Promise
<
{
[
key
:
string
]:
any
;
}
>
>
;
let
dynamicViewsModules
:
Record
<
string
,
()
=>
Promise
<
Recordable
>>
;
//
动态引入
//
Dynamic introduction
function
asyncImportRoute
(
routes
:
AppRouteRecordRaw
[]
|
undefined
)
{
dynamicViewsModules
=
dynamicViewsModules
||
import
.
meta
.
glob
(
'
../../views/**/*.{vue,tsx}
'
);
if
(
!
routes
)
return
;
...
...
@@ -26,19 +22,14 @@ function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
if
(
component
)
{
item
.
component
=
dynamicImport
(
dynamicViewsModules
,
component
as
string
);
}
else
if
(
name
)
{
item
.
component
=
getParentLayout
(
name
);
item
.
component
=
getParentLayout
();
}
children
&&
asyncImportRoute
(
children
);
});
}
function
dynamicImport
(
dynamicViewsModules
:
Record
<
string
,
()
=>
Promise
<
{
[
key
:
string
]:
any
;
}
>
>
,
dynamicViewsModules
:
Record
<
string
,
()
=>
Promise
<
Recordable
>>
,
component
:
string
)
{
const
keys
=
Object
.
keys
(
dynamicViewsModules
);
...
...
@@ -84,18 +75,69 @@ export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModul
return
(
routeList
as
unknown
)
as
T
[];
}
// Return to the new routing structure, not affected by the original example
export
function
getRoute
(
route
:
RouteLocationNormalized
):
RouteLocationNormalized
{
if
(
!
route
)
return
route
;
const
{
matched
,
...
opt
}
=
route
;
return
{
...
opt
,
matched
:
(
matched
?
matched
.
map
((
item
)
=>
({
meta
:
item
.
meta
,
name
:
item
.
name
,
path
:
item
.
path
,
}))
:
undefined
)
as
RouteRecordNormalized
[],
};
/**
* Convert multi-level routing to level 2 routing
*/
export
function
flatRoutes
(
routeModules
:
AppRouteModule
[])
{
for
(
let
index
=
0
;
index
<
routeModules
.
length
;
index
++
)
{
const
routeModule
=
routeModules
[
index
];
if
(
!
isMultipleRoute
(
routeModule
))
{
continue
;
}
promoteRouteLevel
(
routeModule
);
}
}
// Routing level upgrade
function
promoteRouteLevel
(
routeModule
:
AppRouteModule
)
{
// Use vue-router to splice menus
let
router
:
Router
|
null
=
createRouter
({
routes
:
[
routeModule
as
any
],
history
:
createWebHashHistory
(),
});
const
routes
=
router
.
getRoutes
();
const
children
=
cloneDeep
(
routeModule
.
children
);
addToChildren
(
routes
,
children
||
[],
routeModule
);
router
=
null
;
routeModule
.
children
=
routeModule
.
children
?.
filter
((
item
)
=>
!
item
.
children
?.
length
);
}
// Add all sub-routes to the secondary route
function
addToChildren
(
routes
:
RouteRecordNormalized
[],
children
:
AppRouteRecordRaw
[],
routeModule
:
AppRouteModule
)
{
for
(
let
index
=
0
;
index
<
children
.
length
;
index
++
)
{
const
child
=
children
[
index
];
const
route
=
routes
.
find
((
item
)
=>
item
.
name
===
child
.
name
);
if
(
route
)
{
routeModule
.
children
=
routeModule
.
children
||
[];
routeModule
.
children
?.
push
(
route
as
any
);
if
(
child
.
children
?.
length
)
{
addToChildren
(
routes
,
child
.
children
,
routeModule
);
}
}
}
}
// Determine whether the level exceeds 2 levels
function
isMultipleRoute
(
routeModule
:
AppRouteModule
)
{
if
(
!
routeModule
||
!
Reflect
.
has
(
routeModule
,
'
children
'
)
||
!
routeModule
.
children
?.
length
)
{
return
false
;
}
const
children
=
routeModule
.
children
;
let
flag
=
false
;
for
(
let
index
=
0
;
index
<
children
.
length
;
index
++
)
{
const
child
=
children
[
index
];
if
(
child
.
children
?.
length
)
{
flag
=
true
;
break
;
}
}
return
flag
;
}
src/router/menus/index.ts
View file @
e12c588c
...
...
@@ -5,6 +5,7 @@ import { appStore } from '/@/store/modules/app';
import
{
permissionStore
}
from
'
/@/store/modules/permission
'
;
import
{
transformMenuModule
,
getAllParentPath
}
from
'
/@/router/helper/menuHelper
'
;
import
{
filter
}
from
'
/@/utils/helper/treeHelper
'
;
import
{
isUrl
}
from
'
/@/utils/is
'
;
import
router
from
'
/@/router
'
;
import
{
PermissionModeEnum
}
from
'
/@/enums/appEnum
'
;
import
{
pathToRegexp
}
from
'
path-to-regexp
'
;
...
...
@@ -19,8 +20,6 @@ Object.keys(modules).forEach((key) => {
menuModules
.
push
(...
modList
);
});
const
reg
=
/
(((
https
?
:
(?:\/\/)?)(?:[
-;:&=
\+\$
,
\w]
+@
)?[
A-Za-z0-9.-
]
+
(?:
:
\d
+
)?
|
(?:
www.|
[
-;:&=
\+\$
,
\w]
+@
)[
A-Za-z0-9.-
]
+
)((?:\/[\+
~%
\/
.
\w
-_
]
*
)?\??(?:[
-
\+
=&;%@.
\w
_
]
*
)
#
?(?:[\w]
*
))?)
$/
;
// ===========================
// ==========Helper===========
// ===========================
...
...
@@ -40,18 +39,15 @@ const staticMenus: Menu[] = [];
})();
async
function
getAsyncMenus
()
{
// 前端角色控制菜单 直接取菜单文件
return
!
isBackMode
()
?
staticMenus
:
permissionStore
.
getBackMenuListState
;
}
// 获取菜单 树级
export
const
getMenus
=
async
():
Promise
<
Menu
[]
>
=>
{
const
menus
=
await
getAsyncMenus
();
const
routes
=
router
.
getRoutes
();
return
!
isBackMode
()
?
filter
(
menus
,
basicFilter
(
routes
))
:
menus
;
};
// 获取当前路径的顶级路径
export
async
function
getCurrentParentPath
(
currentPath
:
string
)
{
const
menus
=
await
getAsyncMenus
();
...
...
@@ -60,7 +56,7 @@ export async function getCurrentParentPath(currentPath: string) {
return
allParentPath
?.[
0
];
}
//
获取1级菜单,删除
children
//
Get the level 1 menu, delete
children
export
async
function
getShallowMenus
():
Promise
<
Menu
[]
>
{
const
menus
=
await
getAsyncMenus
();
const
routes
=
router
.
getRoutes
();
...
...
@@ -68,7 +64,7 @@ export async function getShallowMenus(): Promise<Menu[]> {
return
!
isBackMode
()
?
shallowMenuList
.
filter
(
basicFilter
(
routes
))
:
shallowMenuList
;
}
//
获取菜单的children
//
Get the children of the menu
export
async
function
getChildrenMenus
(
parentPath
:
string
)
{
const
menus
=
await
getAsyncMenus
();
const
parent
=
menus
.
find
((
item
)
=>
item
.
path
===
parentPath
);
...
...
@@ -78,14 +74,10 @@ export async function getChildrenMenus(parentPath: string) {
return
!
isBackMode
()
?
filter
(
parent
.
children
,
basicFilter
(
routes
))
:
parent
.
children
;
}
// 通用过滤方法
function
basicFilter
(
routes
:
RouteRecordNormalized
[])
{
return
(
menu
:
Menu
)
=>
{
const
matchRoute
=
routes
.
find
((
route
)
=>
{
const
match
=
route
.
path
.
match
(
reg
)?.[
0
];
if
(
match
&&
match
===
menu
.
path
)
{
return
true
;
}
if
(
isUrl
(
menu
.
path
))
return
true
;
if
(
route
.
meta
?.
carryParam
)
{
return
pathToRegexp
(
route
.
path
).
test
(
menu
.
path
);
...
...
src/router/routes/basic.ts
0 → 100644
View file @
e12c588c
import
type
{
AppRouteRecordRaw
}
from
'
/@/router/types
'
;
import
{
t
}
from
'
/@/hooks/web/useI18n
'
;
import
{
REDIRECT_NAME
,
LAYOUT
,
EXCEPTION_COMPONENT
}
from
'
/@/router/constant
'
;
// 404 on a page
export
const
PAGE_NOT_FOUND_ROUTE
:
AppRouteRecordRaw
=
{
path
:
'
/:path(.*)*
'
,
name
:
'
ErrorPage
'
,
component
:
LAYOUT
,
meta
:
{
title
:
'
ErrorPage
'
,
hideBreadcrumb
:
true
,
},
children
:
[
{
path
:
'
/:path(.*)*
'
,
name
:
'
ErrorPage
'
,
component
:
EXCEPTION_COMPONENT
,
meta
:
{
title
:
'
ErrorPage
'
,
hideBreadcrumb
:
true
,
},
},
],
};
export
const
REDIRECT_ROUTE
:
AppRouteRecordRaw
=
{
path
:
'
/redirect
'
,
name
:
REDIRECT_NAME
,
component
:
LAYOUT
,
meta
:
{
title
:
REDIRECT_NAME
,
hideBreadcrumb
:
true
,
},
children
:
[
{
path
:
'
/redirect/:path(.*)
'
,
name
:
REDIRECT_NAME
,
component
:
()
=>
import
(
'
/@/views/sys/redirect/index.vue
'
),
meta
:
{
title
:
REDIRECT_NAME
,
hideBreadcrumb
:
true
,
},
},
],
};
export
const
ERROR_LOG_ROUTE
:
AppRouteRecordRaw
=
{
path
:
'
/error-log
'
,
name
:
'
errorLog
'
,
component
:
LAYOUT
,
meta
:
{
title
:
'
ErrorLog
'
,
hideBreadcrumb
:
true
,
},
children
:
[
{
path
:
'
list
'
,
name
:
'
errorLogList
'
,
component
:
()
=>
import
(
'
/@/views/sys/error-log/index.vue
'
),
meta
:
{
title
:
t
(
'
routes.basic.errorLogList
'
),
hideBreadcrumb
:
true
,
},
},
],
};
src/router/routes/index.ts
View file @
e12c588c
import
type
{
AppRouteRecordRaw
,
AppRouteModule
}
from
'
/@/router/types
'
;
import
{
PAGE_NOT_FOUND_ROUTE
,
REDIRECT_ROUTE
}
from
'
../constant
'
;
import
{
PAGE_NOT_FOUND_ROUTE
,
REDIRECT_ROUTE
}
from
'
/@/router/routes/basic
'
;
import
{
mainOutRoutes
}
from
'
./mainOut
'
;
import
{
PageEnum
}
from
'
/@/enums/pageEnum
'
;
import
{
t
}
from
'
/@/hooks/web/useI18n
'
;
import
{
flatRoutes
}
from
'
/@/router/helper/routeHelper
'
;
const
modules
=
import
.
meta
.
globEager
(
'
./modules/**/*.ts
'
);
...
...
@@ -16,6 +17,9 @@ Object.keys(modules).forEach((key) => {
routeModuleList
.
push
(...
modList
);
});
// Multi-level routing conversion
flatRoutes
(
routeModuleList
);
export
const
asyncRoutes
=
[
PAGE_NOT_FOUND_ROUTE
,
...
routeModuleList
];
export
const
RootRoute
:
AppRouteRecordRaw
=
{
...
...
src/store/modules/permission.ts
View file @
e12c588c
...
...
@@ -14,12 +14,12 @@ import { filter } from '/@/utils/helper/treeHelper';
import
{
toRaw
}
from
'
vue
'
;
import
{
getMenuListById
}
from
'
/@/api/sys/menu
'
;
import
{
transformObjToRoute
}
from
'
/@/router/helper/routeHelper
'
;
import
{
transformObjToRoute
,
flatRoutes
}
from
'
/@/router/helper/routeHelper
'
;
import
{
transformRouteToMenu
}
from
'
/@/router/helper/menuHelper
'
;
import
{
useMessage
}
from
'
/@/hooks/web/useMessage
'
;
import
{
useI18n
}
from
'
/@/hooks/web/useI18n
'
;
import
{
ERROR_LOG_ROUTE
,
PAGE_NOT_FOUND_ROUTE
}
from
'
/@/router/
constant
'
;
import
{
ERROR_LOG_ROUTE
,
PAGE_NOT_FOUND_ROUTE
}
from
'
/@/router/
routes/basic
'
;
const
{
createMessage
}
=
useMessage
();
const
NAME
=
'
app-permission
'
;
...
...
@@ -113,11 +113,12 @@ class Permission extends VuexModule {
// Dynamically introduce components
routeList
=
transformObjToRoute
(
routeList
);
// Background routing to menu structure
const
backMenuList
=
transformRouteToMenu
(
routeList
);
this
.
commitBackMenuListState
(
backMenuList
);
flatRoutes
(
routeList
);
routes
=
[
PAGE_NOT_FOUND_ROUTE
,
...
routeList
];
}
routes
.
push
(
ERROR_LOG_ROUTE
);
...
...
src/store/modules/tab.ts
View file @
e12c588c
...
...
@@ -8,8 +8,8 @@ import { PageEnum } from '/@/enums/pageEnum';
import
store
from
'
/@/store
'
;
import
router
from
'
/@/router
'
;
import
{
PAGE_NOT_FOUND_ROUTE
,
REDIRECT_ROUTE
}
from
'
/@/router/
constant
'
;
import
{
getR
oute
}
from
'
/@/router/helper/routeHelper
'
;
import
{
PAGE_NOT_FOUND_ROUTE
,
REDIRECT_ROUTE
}
from
'
/@/router/
routes/basic
'
;
import
{
getR
awRoute
}
from
'
/@/utils
'
;
import
{
useGo
,
useRedo
}
from
'
/@/hooks/web/usePage
'
;
import
{
cloneDeep
}
from
'
lodash-es
'
;
...
...
@@ -18,8 +18,6 @@ const NAME = 'app-tab';
hotModuleUnregisterModule
(
NAME
);
export
const
PAGE_LAYOUT_KEY
=
'
__PAGE_LAYOUT__
'
;
function
isGotoPage
()
{
const
go
=
useGo
();
go
(
unref
(
router
.
currentRoute
).
path
,
true
);
...
...
@@ -27,7 +25,7 @@ function isGotoPage() {
@
Module
({
namespaced
:
true
,
name
:
NAME
,
dynamic
:
true
,
store
})
class
Tab
extends
VuexModule
{
cached
MapState
=
new
Map
<
string
,
string
[]
>
();
cached
TabsState
:
Set
<
string
>
=
new
Set
();
// tab list
tabsState
:
RouteLocationNormalized
[]
=
[];
...
...
@@ -43,8 +41,8 @@ class Tab extends VuexModule {
return
this
.
tabsState
.
find
((
item
)
=>
item
.
path
===
route
.
path
)
!
;
}
get
getCached
MapState
():
Map
<
string
,
string
[]
>
{
return
this
.
cachedMapState
;
get
getCached
TabsState
():
string
[]
{
return
Array
.
from
(
this
.
cachedTabsState
)
;
}
get
getLastDragEndIndexState
():
number
{
...
...
@@ -53,7 +51,7 @@ class Tab extends VuexModule {
@
Mutation
commitClearCache
():
void
{
this
.
cached
MapState
=
new
Map
();
this
.
cached
TabsState
=
new
Set
();
}
@
Mutation
...
...
@@ -77,46 +75,16 @@ class Tab extends VuexModule {
@
Mutation
commitCachedMapState
():
void
{
const
cacheMap
=
new
Map
<
string
,
string
[]
>
();
const
cacheMap
:
Set
<
string
>
=
new
Set
();
const
pageCacheSet
=
new
Set
<
string
>
();
this
.
tabsState
.
forEach
((
tab
)
=>
{
const
item
=
getRoute
(
tab
);
const
item
=
getR
awR
oute
(
tab
);
const
needCache
=
!
item
.
meta
?.
ignoreKeepAlive
;
if
(
!
needCache
)
return
;
if
(
item
.
meta
?.
affix
)
{
const
name
=
item
.
name
as
string
;
pageCacheSet
.
add
(
name
);
}
else
if
(
item
?.
matched
&&
needCache
)
{
const
matched
=
item
?.
matched
;
if
(
!
matched
)
return
;
const
len
=
matched
.
length
;
if
(
len
<
2
)
return
;
for
(
let
i
=
0
;
i
<
matched
.
length
;
i
++
)
{
const
key
=
matched
[
i
].
name
as
string
;
if
(
i
<
2
)
{
pageCacheSet
.
add
(
key
);
}
if
(
i
<
len
-
1
)
{
const
{
meta
,
name
}
=
matched
[
i
+
1
];
if
(
meta
&&
(
meta
.
affix
||
needCache
))
{
const
mapList
=
cacheMap
.
get
(
key
)
||
[];
if
(
!
mapList
.
includes
(
name
as
string
))
{
mapList
.
push
(
name
as
string
);
}
cacheMap
.
set
(
key
,
mapList
);
}
}
}
}
const
name
=
item
.
name
as
string
;
cacheMap
.
add
(
name
);
});
cacheMap
.
set
(
PAGE_LAYOUT_KEY
,
Array
.
from
(
pageCacheSet
));
this
.
cachedMapState
=
cacheMap
;
this
.
cachedTabsState
=
cacheMap
;
}
@
Mutation
...
...
@@ -162,7 +130,7 @@ class Tab extends VuexModule {
@
Mutation
commitResetState
():
void
{
this
.
tabsState
=
[];
this
.
cached
MapState
=
new
Map
();
this
.
cached
TabsState
=
new
Set
();
}
@
Mutation
...
...
@@ -190,7 +158,7 @@ class Tab extends VuexModule {
)
{
return
;
}
this
.
commitTabRoutesState
(
getRoute
(
route
));
this
.
commitTabRoutesState
(
getR
awR
oute
(
route
));
this
.
commitCachedMapState
();
}
...
...
@@ -198,17 +166,12 @@ class Tab extends VuexModule {
@
Mutation
async
commitRedoPage
()
{
const
route
=
router
.
currentRoute
.
value
;
for
(
const
[
key
,
value
]
of
this
.
cachedMapState
)
{
const
index
=
value
.
findIndex
((
item
)
=>
item
===
(
route
.
name
as
string
));
if
(
index
===
-
1
)
{
continue
;
}
if
(
value
.
length
===
1
)
{
this
.
cachedMapState
.
delete
(
key
);
continue
;
}
value
.
splice
(
index
,
1
);
this
.
cachedMapState
.
set
(
key
,
value
);
const
name
=
route
.
name
;
const
findVal
=
Array
.
from
(
this
.
cachedTabsState
).
find
((
item
)
=>
item
===
name
);
if
(
findVal
)
{
this
.
cachedTabsState
.
delete
(
findVal
);
// this.cachedTabsState.splice(index, 1);
}
const
redo
=
useRedo
();
await
redo
();
...
...
src/utils/index.ts
View file @
e12c588c
export
const
timestamp
=
()
=>
+
Date
.
now
()
;
import
type
{
RouteLocationNormalized
,
RouteRecordNormalized
}
from
'
vue-router
'
;
import
{
unref
}
from
'
vue
'
;
import
{
isObject
}
from
'
/@/utils/is
'
;
export
const
clamp
=
(
n
:
number
,
min
:
number
,
max
:
number
)
=>
Math
.
min
(
max
,
Math
.
max
(
min
,
n
));
export
const
noop
=
()
=>
{};
export
const
now
=
()
=>
Date
.
now
();
/**
* @description: Set ui mount node
...
...
@@ -91,3 +90,18 @@ export function setTitle(title: string, appTitle?: string) {
setDocumentTitle
(
_title
);
}
}
export
function
getRawRoute
(
route
:
RouteLocationNormalized
):
RouteLocationNormalized
{
if
(
!
route
)
return
route
;
const
{
matched
,
...
opt
}
=
route
;
return
{
...
opt
,
matched
:
(
matched
?
matched
.
map
((
item
)
=>
({
meta
:
item
.
meta
,
name
:
item
.
name
,
path
:
item
.
path
,
}))
:
undefined
)
as
RouteRecordNormalized
[],
};
}
vite.config.ts
View file @
e12c588c
...
...
@@ -43,7 +43,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
},
build
:
{
minify
:
'
esbuild
'
,
//
minify: 'esbuild',
outDir
:
OUTPUT_DIR
,
polyfillDynamicImport
:
VITE_LEGACY
,
terserOptions
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment