@duxweb/dvha-core 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE +165 -0
- package/README.md +0 -0
- package/package.json +27 -0
- package/src/components/common/index.ts +1 -0
- package/src/components/common/logo.tsx +62 -0
- package/src/components/index.ts +3 -0
- package/src/components/loader/iframe.tsx +12 -0
- package/src/components/loader/index.ts +1 -0
- package/src/components/overlay/index.ts +1 -0
- package/src/components/overlay/overlay.tsx +84 -0
- package/src/hooks/auth.ts +261 -0
- package/src/hooks/config.ts +16 -0
- package/src/hooks/data.ts +648 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/manage.ts +71 -0
- package/src/hooks/menu.ts +146 -0
- package/src/hooks/overlay.ts +21 -0
- package/src/hooks/theme.ts +49 -0
- package/src/index.ts +9 -0
- package/src/main.ts +28 -0
- package/src/provider/app.tsx +179 -0
- package/src/provider/index.ts +2 -0
- package/src/provider/tab.tsx +76 -0
- package/src/router/index.ts +1 -0
- package/src/router/route.ts +47 -0
- package/src/simple/authProvider.ts +99 -0
- package/src/simple/dataProvider.ts +153 -0
- package/src/simple/index.ts +2 -0
- package/src/stores/auth.ts +73 -0
- package/src/stores/index.ts +3 -0
- package/src/stores/route.ts +159 -0
- package/src/stores/tab.ts +120 -0
- package/src/types/auth.ts +44 -0
- package/src/types/config.ts +49 -0
- package/src/types/data.ts +108 -0
- package/src/types/index.ts +6 -0
- package/src/types/manage.ts +40 -0
- package/src/types/menu.ts +24 -0
- package/src/types/theme.ts +12 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/tree.ts +63 -0
- package/tsconfig.json +41 -0
- package/typings.d.ts +10 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { IMenu } from '../types'
|
|
2
|
+
import { cloneDeep } from 'lodash-es'
|
|
3
|
+
import { storeToRefs } from 'pinia'
|
|
4
|
+
import { computed, ref, watch } from 'vue'
|
|
5
|
+
import { useRouteStore } from '../stores'
|
|
6
|
+
import { arrayToTree, searchTree } from '../utils'
|
|
7
|
+
import { useRoute } from 'vue-router'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export interface UseMenuProps {
|
|
11
|
+
doubleMenu?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function useMenu(props?: UseMenuProps) {
|
|
15
|
+
const routeStore = useRouteStore()
|
|
16
|
+
const { routes } = storeToRefs(routeStore)
|
|
17
|
+
|
|
18
|
+
const getMenu = (hidden: boolean = true): IMenu[] => {
|
|
19
|
+
return cloneDeep(routes.value)?.filter(item => !!item?.name).filter(item => !hidden || item.hidden === undefined || item.hidden === false)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const originalList = computed<Record<string, any>[]>(() => {
|
|
23
|
+
const menus = getMenu(false)
|
|
24
|
+
return arrayToTree(menus, {
|
|
25
|
+
idKey: 'name',
|
|
26
|
+
parentKey: 'parent',
|
|
27
|
+
childrenKey: 'children',
|
|
28
|
+
sortKey: 'sort',
|
|
29
|
+
}, undefined)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const list = computed<Record<string, any>[]>(() => {
|
|
33
|
+
const menus = getMenu()
|
|
34
|
+
const data = arrayToTree(menus, {
|
|
35
|
+
idKey: 'name',
|
|
36
|
+
parentKey: 'parent',
|
|
37
|
+
childrenKey: 'children',
|
|
38
|
+
sortKey: 'sort',
|
|
39
|
+
}, undefined)
|
|
40
|
+
return data
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
const route = useRoute()
|
|
45
|
+
|
|
46
|
+
const allKey = ref(route.name)
|
|
47
|
+
const appKey = ref(route.name)
|
|
48
|
+
const subKey = ref(route.name)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
const mainMenu = computed(() => {
|
|
52
|
+
if (props?.doubleMenu) {
|
|
53
|
+
return list.value
|
|
54
|
+
}
|
|
55
|
+
const appList = cloneDeep(list.value)
|
|
56
|
+
return appList?.map((item) => {
|
|
57
|
+
delete item.children
|
|
58
|
+
return item
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const subMenu = computed(() => {
|
|
63
|
+
if (props?.doubleMenu) {
|
|
64
|
+
return []
|
|
65
|
+
}
|
|
66
|
+
const subList = list.value?.find(item => item.name === appKey.value)?.children
|
|
67
|
+
return subList || []
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const crumbs = computed(() => {
|
|
71
|
+
const data = searchTree(originalList.value, (item) => {
|
|
72
|
+
return item?.name === route.name
|
|
73
|
+
})
|
|
74
|
+
return data
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
watch(() => props?.doubleMenu, () => {
|
|
78
|
+
if (!props?.doubleMenu) {
|
|
79
|
+
const paths = searchTree(list.value, (item) => {
|
|
80
|
+
return item?.name === subKey.value
|
|
81
|
+
})
|
|
82
|
+
appKey.value = paths?.[paths.length - 1]?.name
|
|
83
|
+
subKey.value = paths?.[paths.length - 1]?.name
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
const paths = searchTree(list.value, (item) => {
|
|
87
|
+
return item?.name === appKey.value
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
appKey.value = paths?.[0]?.name
|
|
91
|
+
subKey.value = paths?.[paths.length - 1]?.name
|
|
92
|
+
}
|
|
93
|
+
}, { immediate: true })
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
const isSubMenu = computed(() => {
|
|
97
|
+
if (!props?.doubleMenu) {
|
|
98
|
+
return true
|
|
99
|
+
}
|
|
100
|
+
return (props?.doubleMenu || subMenu.value.length > 0)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
watch([route, originalList, () => props?.doubleMenu], () => {
|
|
104
|
+
const paths = searchTree(originalList.value, (item) => {
|
|
105
|
+
return item.name === route.name
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const findIndex = (list) => {
|
|
109
|
+
let index = -1
|
|
110
|
+
for (let i = list.length - 1; i >= 0; i--) {
|
|
111
|
+
if (list[i].hidden === false || list[i].hidden === undefined) {
|
|
112
|
+
index = i
|
|
113
|
+
break
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return index
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const subIndex = findIndex(paths)
|
|
120
|
+
|
|
121
|
+
allKey.value = paths?.[subIndex]?.name
|
|
122
|
+
|
|
123
|
+
if (props?.doubleMenu) {
|
|
124
|
+
appKey.value = paths?.[subIndex]?.name
|
|
125
|
+
subKey.value = paths?.[subIndex]?.name
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
appKey.value = paths?.[0]?.name
|
|
129
|
+
subKey.value = paths?.[subIndex]?.name
|
|
130
|
+
}
|
|
131
|
+
}, { immediate: true })
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
data: list,
|
|
136
|
+
originalData: originalList,
|
|
137
|
+
getMenu,
|
|
138
|
+
mainMenu,
|
|
139
|
+
subMenu,
|
|
140
|
+
isSubMenu,
|
|
141
|
+
crumbs,
|
|
142
|
+
active: allKey,
|
|
143
|
+
appActive: appKey,
|
|
144
|
+
subActive: subKey,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useOverlayInject } from "@overlastic/vue"
|
|
2
|
+
import { DuxOverlay } from "../components"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export interface UseOverlayProps {
|
|
6
|
+
component?: () => any
|
|
7
|
+
componentProps?: Record<string, any>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const useOverlay = () => {
|
|
11
|
+
|
|
12
|
+
const create = useOverlayInject(DuxOverlay)
|
|
13
|
+
|
|
14
|
+
const show = (props: UseOverlayProps) => {
|
|
15
|
+
return create(props)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
show,
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { BasicColorSchema, useColorMode, UseColorModeOptions, useCycleList } from '@vueuse/core'
|
|
2
|
+
import { computed, nextTick, ref, watch, watchEffect } from 'vue'
|
|
3
|
+
import { useManage } from './manage'
|
|
4
|
+
import { ITheme } from '../types'
|
|
5
|
+
|
|
6
|
+
// 扩散效果配置接口
|
|
7
|
+
export interface RippleOptions {
|
|
8
|
+
duration?: number
|
|
9
|
+
easing?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const useTheme = (options?: UseColorModeOptions) => {
|
|
13
|
+
const colorMode = useColorMode(options)
|
|
14
|
+
const manage = useManage()
|
|
15
|
+
|
|
16
|
+
const { state, next } = useCycleList(['dark', 'light', 'auto'] as const, {
|
|
17
|
+
initialValue: colorMode,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
watchEffect(() => colorMode.value = state.value)
|
|
21
|
+
|
|
22
|
+
const isDark = computed(() => {
|
|
23
|
+
const { system, store } = colorMode
|
|
24
|
+
if (state.value === 'auto') {
|
|
25
|
+
return system.value === 'dark'
|
|
26
|
+
}
|
|
27
|
+
return store.value === 'dark'
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const theme = computed<ITheme>(() => {
|
|
31
|
+
if (isDark.value) {
|
|
32
|
+
return {
|
|
33
|
+
logo: manage.config.theme?.darkLogo,
|
|
34
|
+
banner: manage.config.theme?.darkBanner,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
logo: manage.config.theme?.logo,
|
|
39
|
+
banner: manage.config.theme?.banner,
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
toggle: next,
|
|
45
|
+
mode: state,
|
|
46
|
+
isDark,
|
|
47
|
+
theme,
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/index.ts
ADDED
package/src/main.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ref, type App } from 'vue'
|
|
2
|
+
import type { IConfig } from './types'
|
|
3
|
+
import { createPinia } from 'pinia'
|
|
4
|
+
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
|
5
|
+
import { initRouter } from './router/route'
|
|
6
|
+
|
|
7
|
+
export function createDux(config: IConfig) {
|
|
8
|
+
const pinia = createPinia()
|
|
9
|
+
pinia.use(piniaPluginPersistedstate)
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
install(app: App) {
|
|
13
|
+
|
|
14
|
+
console.log(
|
|
15
|
+
`%c dux-vue %c dux.cn %c`,
|
|
16
|
+
'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
|
|
17
|
+
'background:#41b883 ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff',
|
|
18
|
+
'background:transparent'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const manageRef = ref<string>()
|
|
22
|
+
app.provide('dux.config', config)
|
|
23
|
+
app.provide('dux.manage', manageRef)
|
|
24
|
+
app.use(initRouter(config))
|
|
25
|
+
app.use(pinia)
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { defineComponent, inject, Ref } from 'vue'
|
|
2
|
+
import { useRouter } from 'vue-router'
|
|
3
|
+
import { useConfig, useManage } from '../hooks'
|
|
4
|
+
import { useAuthStore, useRouteStore } from '../stores'
|
|
5
|
+
import { storeToRefs } from 'pinia'
|
|
6
|
+
import { IMenu } from '../types'
|
|
7
|
+
import { OverlaysProvider } from '@overlastic/vue'
|
|
8
|
+
|
|
9
|
+
export const DuxAppProvider = defineComponent({
|
|
10
|
+
name: 'DuxAppProvider',
|
|
11
|
+
props: {
|
|
12
|
+
},
|
|
13
|
+
setup(_props, { slots }) {
|
|
14
|
+
const manageRef = inject<Ref<string>>('dux.manage')
|
|
15
|
+
|
|
16
|
+
const config = useConfig()
|
|
17
|
+
const router = useRouter()
|
|
18
|
+
const authStore = useAuthStore()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
router.beforeEach(async (to, _from, next) => {
|
|
22
|
+
|
|
23
|
+
const manageName = to.meta.manageName as string
|
|
24
|
+
const noAuth = to.meta.authorization === false
|
|
25
|
+
|
|
26
|
+
if (!manageName) {
|
|
27
|
+
const defaultManage = config.defaultManage || config.manages?.[0]?.name || ''
|
|
28
|
+
return next({
|
|
29
|
+
path: `/${defaultManage}`,
|
|
30
|
+
replace: true,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (manageRef) {
|
|
35
|
+
manageRef.value = manageName
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const routeStore = useRouteStore(manageName)
|
|
39
|
+
const { routes } = storeToRefs(routeStore)
|
|
40
|
+
const manage = useManage(manageName)
|
|
41
|
+
|
|
42
|
+
// unlogin handle
|
|
43
|
+
if (!authStore.isLogin(manageName)) {
|
|
44
|
+
|
|
45
|
+
if (noAuth) {
|
|
46
|
+
return next()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return next({
|
|
50
|
+
path: manage.getRoutePath(`login`),
|
|
51
|
+
replace: true,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const formatMenus = (menus: IMenu[]) => {
|
|
56
|
+
return menus?.map((item: IMenu) => {
|
|
57
|
+
return {
|
|
58
|
+
...item,
|
|
59
|
+
path: manage.getRoutePath(item.path || ''),
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// init route
|
|
65
|
+
if (!routeStore.getRouteInit()) {
|
|
66
|
+
|
|
67
|
+
// components
|
|
68
|
+
const components = manage.config?.components || {}
|
|
69
|
+
const commonRoutes: IMenu[] = []
|
|
70
|
+
|
|
71
|
+
if (components.notFound) {
|
|
72
|
+
commonRoutes.push({
|
|
73
|
+
name: `${manageName}.notFound`,
|
|
74
|
+
label: '404',
|
|
75
|
+
path: ':pathMatch(.*)*',
|
|
76
|
+
component: components.notFound,
|
|
77
|
+
hidden: true,
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (components.notAuthorized) {
|
|
82
|
+
commonRoutes.push({
|
|
83
|
+
name: `${manageName}.notAuthorized`,
|
|
84
|
+
label: '403',
|
|
85
|
+
path: 'notAuthorized',
|
|
86
|
+
component: components.notAuthorized,
|
|
87
|
+
hidden: true,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (components.error) {
|
|
92
|
+
commonRoutes.push({
|
|
93
|
+
name: `${manageName}.error`,
|
|
94
|
+
label: '500',
|
|
95
|
+
path: 'error',
|
|
96
|
+
component: components.error,
|
|
97
|
+
hidden: true,
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
// init local route
|
|
103
|
+
routeStore.setRoutes(formatMenus(manage.config?.menus || []))
|
|
104
|
+
|
|
105
|
+
// init remote route
|
|
106
|
+
if (manage.config?.apiRoutePath) {
|
|
107
|
+
try {
|
|
108
|
+
await manage.config.dataProvider?.custom({
|
|
109
|
+
path: manage.config.apiRoutePath,
|
|
110
|
+
meta: {
|
|
111
|
+
timeout: 5000,
|
|
112
|
+
}
|
|
113
|
+
}, manage, authStore.getUser(manageName)).then((res) => {
|
|
114
|
+
routeStore.appendRoutes(formatMenus(res.data || []))
|
|
115
|
+
})
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error(error)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// init common routes
|
|
122
|
+
routeStore.appendRoutes(commonRoutes)
|
|
123
|
+
|
|
124
|
+
// register route
|
|
125
|
+
routes.value.forEach((item: IMenu) => {
|
|
126
|
+
if (!item.path) {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
router.addRoute(`${manageName}.auth`, {
|
|
131
|
+
name: item.name,
|
|
132
|
+
path: item.path,
|
|
133
|
+
component: typeof item.component === 'function' ? item.component : () => import('../components/loader/iframe'),
|
|
134
|
+
meta: item.meta,
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
// reload route
|
|
140
|
+
return next({
|
|
141
|
+
path: to.fullPath,
|
|
142
|
+
replace: true,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
const pathMatch = [
|
|
148
|
+
'',
|
|
149
|
+
'/',
|
|
150
|
+
`/${manageName}`,
|
|
151
|
+
`/${manageName}/`,
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
// index route redirect
|
|
155
|
+
if (pathMatch.includes(to.path)) {
|
|
156
|
+
const indexRoute = routeStore.getIndexRoute()
|
|
157
|
+
|
|
158
|
+
// if index route is not found
|
|
159
|
+
if (!indexRoute?.path || pathMatch.includes(indexRoute?.path)) {
|
|
160
|
+
console.warn(`[Dux] index route not found, skip redirect`)
|
|
161
|
+
return next()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return next({
|
|
165
|
+
path: indexRoute?.path || '/',
|
|
166
|
+
replace: true,
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return next()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
return () => (
|
|
174
|
+
<OverlaysProvider>
|
|
175
|
+
{slots.default?.()}
|
|
176
|
+
</OverlaysProvider>
|
|
177
|
+
)
|
|
178
|
+
},
|
|
179
|
+
})
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { defineComponent, Transition, KeepAlive, watch } from 'vue'
|
|
2
|
+
import { RouterView, useRoute } from 'vue-router'
|
|
3
|
+
import { useRouteStore, useTabStore } from '../stores'
|
|
4
|
+
|
|
5
|
+
export const DuxTabRouterView = defineComponent({
|
|
6
|
+
name: 'DuxTabRouterView',
|
|
7
|
+
props: {},
|
|
8
|
+
setup() {
|
|
9
|
+
const route = useRoute()
|
|
10
|
+
const tabStore = useTabStore()
|
|
11
|
+
const routeStore = useRouteStore()
|
|
12
|
+
|
|
13
|
+
// route cache
|
|
14
|
+
const cacheMap = new Map()
|
|
15
|
+
|
|
16
|
+
const wrap = (name: string, component: any) => {
|
|
17
|
+
let cache
|
|
18
|
+
const cacheName = name
|
|
19
|
+
|
|
20
|
+
if (cacheMap.has(cacheName)) {
|
|
21
|
+
cache = cacheMap.get(cacheName)
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
cache = {
|
|
25
|
+
name: cacheName,
|
|
26
|
+
render() {
|
|
27
|
+
return component
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
cacheMap.set(cacheName, cache)
|
|
31
|
+
}
|
|
32
|
+
return cache
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
tabStore.$subscribe((_mutation, state) => {
|
|
36
|
+
cacheMap.forEach((cache) => {
|
|
37
|
+
if (!state.tabs.some(t => t.path === cache.name)) {
|
|
38
|
+
cacheMap.delete(cache.name)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// add index route
|
|
44
|
+
const indexRoute = routeStore.getIndexRoute()
|
|
45
|
+
if (indexRoute) {
|
|
46
|
+
tabStore.addTab({...indexRoute, meta: { ...indexRoute.meta, lock: true } })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// watch route and routeStore.routes
|
|
50
|
+
watch([route, () => routeStore.routes], () => {
|
|
51
|
+
const info = routeStore.searchRouteName(route.name as string)
|
|
52
|
+
if (!info) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
const item = { label: info.label as string, path: route.path, name: info.name }
|
|
56
|
+
tabStore.addTab(item)
|
|
57
|
+
}, { immediate: true })
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
return () => (
|
|
61
|
+
<RouterView>
|
|
62
|
+
{{
|
|
63
|
+
default: ({Component}) => {
|
|
64
|
+
return (
|
|
65
|
+
<Transition name="tab-fade" mode="out-in" appear>
|
|
66
|
+
<KeepAlive include={tabStore.tabs.map(t => t.path || '')}>
|
|
67
|
+
<Component is={wrap(route.path, Component)} key={route.path} />
|
|
68
|
+
</KeepAlive>
|
|
69
|
+
</Transition>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}}
|
|
73
|
+
</RouterView>
|
|
74
|
+
)
|
|
75
|
+
},
|
|
76
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './route'
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { RouteRecordRaw } from 'vue-router'
|
|
2
|
+
import type { IConfig } from '../types'
|
|
3
|
+
import { createRouter, createWebHashHistory } from 'vue-router'
|
|
4
|
+
|
|
5
|
+
export function initRouter(config: IConfig) {
|
|
6
|
+
const routes: RouteRecordRaw[] = [
|
|
7
|
+
...config.routes || [],
|
|
8
|
+
{
|
|
9
|
+
name: 'default',
|
|
10
|
+
path: '/:catchAll(.*)',
|
|
11
|
+
redirect: `/${config.defaultManage || config.manages?.[0]?.name || ''}`,
|
|
12
|
+
},
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
config.manages?.forEach((manage) => {
|
|
16
|
+
|
|
17
|
+
const authRoutes = manage.routes?.filter((route) => route.meta?.authorization === true || route.meta?.authorization === undefined) || []
|
|
18
|
+
const noAuthRoutes = manage.routes?.filter((route) => route.meta?.authorization === false) || []
|
|
19
|
+
|
|
20
|
+
routes.push({
|
|
21
|
+
name: manage.name,
|
|
22
|
+
path: manage.routePrefix || '',
|
|
23
|
+
children: [
|
|
24
|
+
{
|
|
25
|
+
path: '',
|
|
26
|
+
name: `${manage.name}.auth`,
|
|
27
|
+
component: manage.components?.authLayout,
|
|
28
|
+
children: authRoutes,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
path: '',
|
|
32
|
+
name: `${manage.name}.noAuth`,
|
|
33
|
+
component: manage.components?.noAuthLayout,
|
|
34
|
+
children: noAuthRoutes,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
meta: {
|
|
38
|
+
manageName: manage.name,
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
return createRouter({
|
|
44
|
+
history: createWebHashHistory(),
|
|
45
|
+
routes,
|
|
46
|
+
})
|
|
47
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
import { IAuthProvider, IAuthLoginResponse, IAuthCheckResponse, IAuthLogoutResponse, IAuthErrorResponse, IAuthActionResponse } from '../types'
|
|
3
|
+
import { IUserState } from '../stores'
|
|
4
|
+
import { IManageHook } from '../hooks'
|
|
5
|
+
|
|
6
|
+
export const simpleAuthProvider: IAuthProvider = {
|
|
7
|
+
login: async (params: any, manage: IManageHook): Promise<IAuthLoginResponse> => {
|
|
8
|
+
return await axios.post(manage.getApiUrl('/login'), params).then((res) => {
|
|
9
|
+
return {
|
|
10
|
+
success: true,
|
|
11
|
+
message: res?.data?.message,
|
|
12
|
+
redirectTo: '/',
|
|
13
|
+
data: res?.data?.data as IUserState,
|
|
14
|
+
}
|
|
15
|
+
}).catch((error) => {
|
|
16
|
+
return {
|
|
17
|
+
success: false,
|
|
18
|
+
message: error?.response?.data?.message || error?.message,
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
},
|
|
22
|
+
check: async (_params?: any, manage?: IManageHook): Promise<IAuthCheckResponse> => {
|
|
23
|
+
return await axios.get(manage?.getApiUrl('/check') || '').then((res: any) => {
|
|
24
|
+
return {
|
|
25
|
+
success: true,
|
|
26
|
+
message: res?.data?.message,
|
|
27
|
+
data: res?.data?.data as IUserState,
|
|
28
|
+
}
|
|
29
|
+
}).catch((error) => {
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
message: error?.response?.data?.message || error?.message,
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
},
|
|
36
|
+
onError: async (error?: any): Promise<IAuthErrorResponse> => {
|
|
37
|
+
if (error.status === 403) {
|
|
38
|
+
return {
|
|
39
|
+
logout: true,
|
|
40
|
+
redirectTo: '/login',
|
|
41
|
+
error,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
logout: false,
|
|
47
|
+
error,
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
logout: async (): Promise<IAuthLogoutResponse> => {
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
redirectTo: '/login',
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
register: async (params: any, manage?: IManageHook): Promise<IAuthLoginResponse> => {
|
|
57
|
+
return await axios.post(manage?.getApiUrl('/auth/register') || '', params).then((res: any) => {
|
|
58
|
+
return {
|
|
59
|
+
success: true,
|
|
60
|
+
message: res?.data?.message,
|
|
61
|
+
redirectTo: '/',
|
|
62
|
+
data: res?.data?.data as IUserState,
|
|
63
|
+
}
|
|
64
|
+
}).catch((error) => {
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
message: error?.response?.data?.message || error?.message,
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
},
|
|
71
|
+
forgotPassword: async (params: any, manage?: IManageHook): Promise<IAuthActionResponse> => {
|
|
72
|
+
return await axios.post(manage?.getApiUrl('/auth/forgot-password') || '', params).then((res: any) => {
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
message: res?.data?.message,
|
|
76
|
+
redirectTo: '/login',
|
|
77
|
+
}
|
|
78
|
+
}).catch((error) => {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
message: error?.response?.data?.message || error?.message,
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
},
|
|
85
|
+
updatePassword: async (params: any, manage?: IManageHook): Promise<IAuthActionResponse> => {
|
|
86
|
+
return await axios.post(manage?.getApiUrl('/auth/update-password') || '', params).then((res: any) => {
|
|
87
|
+
return {
|
|
88
|
+
success: true,
|
|
89
|
+
message: res?.data?.message,
|
|
90
|
+
redirectTo: '/login',
|
|
91
|
+
}
|
|
92
|
+
}).catch((error) => {
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
message: error?.response?.data?.message || error?.message,
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
},
|
|
99
|
+
}
|