@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +165 -0
  3. package/README.md +0 -0
  4. package/package.json +27 -0
  5. package/src/components/common/index.ts +1 -0
  6. package/src/components/common/logo.tsx +62 -0
  7. package/src/components/index.ts +3 -0
  8. package/src/components/loader/iframe.tsx +12 -0
  9. package/src/components/loader/index.ts +1 -0
  10. package/src/components/overlay/index.ts +1 -0
  11. package/src/components/overlay/overlay.tsx +84 -0
  12. package/src/hooks/auth.ts +261 -0
  13. package/src/hooks/config.ts +16 -0
  14. package/src/hooks/data.ts +648 -0
  15. package/src/hooks/index.ts +7 -0
  16. package/src/hooks/manage.ts +71 -0
  17. package/src/hooks/menu.ts +146 -0
  18. package/src/hooks/overlay.ts +21 -0
  19. package/src/hooks/theme.ts +49 -0
  20. package/src/index.ts +9 -0
  21. package/src/main.ts +28 -0
  22. package/src/provider/app.tsx +179 -0
  23. package/src/provider/index.ts +2 -0
  24. package/src/provider/tab.tsx +76 -0
  25. package/src/router/index.ts +1 -0
  26. package/src/router/route.ts +47 -0
  27. package/src/simple/authProvider.ts +99 -0
  28. package/src/simple/dataProvider.ts +153 -0
  29. package/src/simple/index.ts +2 -0
  30. package/src/stores/auth.ts +73 -0
  31. package/src/stores/index.ts +3 -0
  32. package/src/stores/route.ts +159 -0
  33. package/src/stores/tab.ts +120 -0
  34. package/src/types/auth.ts +44 -0
  35. package/src/types/config.ts +49 -0
  36. package/src/types/data.ts +108 -0
  37. package/src/types/index.ts +6 -0
  38. package/src/types/manage.ts +40 -0
  39. package/src/types/menu.ts +24 -0
  40. package/src/types/theme.ts +12 -0
  41. package/src/utils/index.ts +1 -0
  42. package/src/utils/tree.ts +63 -0
  43. package/tsconfig.json +41 -0
  44. package/typings.d.ts +10 -0
@@ -0,0 +1,153 @@
1
+ import axios from 'axios'
2
+ import { IDataProvider, IDataProviderCreateManyOptions, IDataProviderCreateOptions, IDataProviderCustomOptions, IDataProviderDeleteManyOptions, IDataProviderDeleteOptions, IDataProviderGetManyOptions, IDataProviderGetOneOptions, IDataProviderListOptions, IDataProviderUpdateManyOptions, IDataProviderUpdateOptions } from '../types'
3
+ import { IManageHook } from '../hooks'
4
+ import { IUserState } from '../stores'
5
+
6
+ export const simpleDataProvider: IDataProvider = {
7
+
8
+ getList: (options: IDataProviderListOptions, manage?: IManageHook, auth?: IUserState) => {
9
+ const params: Record<string, any> = {}
10
+
11
+ if (options.pagination && typeof options.pagination === 'object') {
12
+ params.page = options.pagination.page
13
+ params.limit = options.pagination.limit
14
+ params.pageSize = options.pagination.pageSize
15
+ }
16
+
17
+ return axios.get(manage?.getApiUrl(options.path) || '', {
18
+ params: {
19
+ ...params,
20
+ ...options.filters,
21
+ ...options.sorters,
22
+ },
23
+ headers: {
24
+ Authorization: auth?.token,
25
+ },
26
+ ...options.meta,
27
+ }).then((res) => {
28
+ return res.data
29
+ })
30
+ },
31
+ create: (options: IDataProviderCreateOptions, manage?: IManageHook, auth?: IUserState) => {
32
+ return axios.post(manage?.getApiUrl(options.path) || '', options.data, {
33
+ headers: {
34
+ Authorization: auth?.token,
35
+ },
36
+ ...options.meta,
37
+ }).then((res) => {
38
+ return res.data
39
+ })
40
+ },
41
+ update: (options: IDataProviderUpdateOptions, manage?: IManageHook, auth?: IUserState) => {
42
+ return axios.put(manage?.getApiUrl(options.id ? `${options.path}/${options.id}` : options.path) || '', options.data, {
43
+ headers: {
44
+ Authorization: auth?.token,
45
+ },
46
+ ...options.meta,
47
+ }).then((res) => {
48
+ return res.data
49
+ })
50
+ },
51
+ deleteOne: (options: IDataProviderDeleteOptions, manage?: IManageHook, auth?: IUserState) => {
52
+ return axios.delete(manage?.getApiUrl(options.id ? `${options.path}/${options.id}` : options.path) || '', {
53
+ headers: {
54
+ Authorization: auth?.token,
55
+ },
56
+ ...options.meta,
57
+ }).then((res) => {
58
+ return res.data
59
+ })
60
+ },
61
+ getOne: (options: IDataProviderGetOneOptions, manage?: IManageHook, auth?: IUserState) => {
62
+ return axios.get(manage?.getApiUrl(options.id ? `${options.path}/${options.id}` : options.path) || '', {
63
+ headers: {
64
+ Authorization: auth?.token,
65
+ },
66
+ ...options.meta,
67
+ }).then((res) => {
68
+ return res.data
69
+ })
70
+ },
71
+ getMany: (options: IDataProviderGetManyOptions, manage?: IManageHook, auth?: IUserState) => {
72
+ return axios.get(manage?.getApiUrl(options.path) || '', {
73
+ params: {
74
+ ids: options.ids,
75
+ },
76
+ headers: {
77
+ Authorization: auth?.token,
78
+ },
79
+ ...options.meta,
80
+ }).then((res) => {
81
+ return res.data
82
+ })
83
+ },
84
+ createMany: (options: IDataProviderCreateManyOptions, manage?: IManageHook, auth?: IUserState) => {
85
+ return axios.post(manage?.getApiUrl(options.path) || '', options.data, {
86
+ headers: {
87
+ Authorization: auth?.token,
88
+ },
89
+ ...options.meta,
90
+ }).then((res) => {
91
+ return res.data
92
+ })
93
+ },
94
+ updateMany: (options: IDataProviderUpdateManyOptions, manage?: IManageHook, auth?: IUserState) => {
95
+ return axios.put(manage?.getApiUrl(options.path) || '', {
96
+ ids: options.ids,
97
+ data: options.data,
98
+ }, {
99
+ headers: {
100
+ Authorization: auth?.token,
101
+ },
102
+ ...options.meta,
103
+ }).then((res) => {
104
+ return res.data
105
+ })
106
+ },
107
+ deleteMany: (options: IDataProviderDeleteManyOptions, manage?: IManageHook, auth?: IUserState) => {
108
+ return axios.delete(manage?.getApiUrl(options.path) || '', {
109
+ params: {
110
+ ids: options.ids,
111
+ },
112
+ headers: {
113
+ Authorization: auth?.token,
114
+ },
115
+ ...options.meta,
116
+ }).then((res) => {
117
+ return res.data
118
+ })
119
+ },
120
+ custom: (options: IDataProviderCustomOptions, manage?: IManageHook, auth?: IUserState) => {
121
+ let params: Record<string, any> = {
122
+ ...options.query,
123
+ }
124
+
125
+ if (options.sorters && typeof options.sorters === 'object') {
126
+ params = {
127
+ ...params,
128
+ ...options.sorters,
129
+ }
130
+ }
131
+
132
+ if (options.filters && typeof options.filters === 'object') {
133
+ params = {
134
+ ...params,
135
+ ...options.filters,
136
+ }
137
+ }
138
+
139
+ return axios.request({
140
+ url: manage?.getApiUrl(options.path || ''),
141
+ method: options.method || 'GET',
142
+ data: options.payload,
143
+ params,
144
+ headers: {
145
+ Authorization: auth?.token,
146
+ ...options.headers,
147
+ },
148
+ ...options.meta,
149
+ }).then((res) => {
150
+ return res.data
151
+ })
152
+ },
153
+ }
@@ -0,0 +1,2 @@
1
+ export * from './authProvider'
2
+ export * from './dataProvider'
@@ -0,0 +1,73 @@
1
+ import { defineStore } from 'pinia'
2
+ import { ref } from 'vue'
3
+
4
+ export interface IUserState {
5
+ token?: string
6
+ id?: number
7
+ info?: Record<string, any>
8
+ permission?: any
9
+ }
10
+
11
+ export const useAuthStore = defineStore('auth', () => {
12
+ const data = ref<Record<string, IUserState | undefined>>({})
13
+
14
+ const isLogin = (manageName: string): boolean => {
15
+ return !!data.value[manageName]
16
+ }
17
+
18
+ const getUser = (manageName: string): IUserState => {
19
+ return data.value[manageName] || {}
20
+ }
21
+
22
+ const login = (manageName: string, params: IUserState) => {
23
+ data.value = {
24
+ ...data.value,
25
+ [manageName]: {
26
+ token: params.token,
27
+ id: params.id,
28
+ info: params.info,
29
+ permission: params.permission,
30
+ },
31
+ }
32
+ }
33
+
34
+ const update = (manageName: string, params: IUserState) => {
35
+ data.value = {
36
+ ...data.value,
37
+ [manageName]: {
38
+ token: params.token,
39
+ id: params.id,
40
+ info: params.info,
41
+ permission: params.permission,
42
+ },
43
+ }
44
+ }
45
+
46
+ const updateKey = (manageName: string, key: string, value: any) => {
47
+ data.value = {
48
+ ...data.value,
49
+ [manageName]: {
50
+ ...data.value[manageName],
51
+ [key]: value,
52
+ },
53
+ }
54
+ }
55
+
56
+ const logout = (manageName: string) => {
57
+ const newData = { ...data.value }
58
+ delete newData[manageName]
59
+ data.value = newData
60
+ }
61
+
62
+ return {
63
+ data,
64
+ getUser,
65
+ login,
66
+ isLogin,
67
+ logout,
68
+ update,
69
+ updateKey,
70
+ }
71
+ }, {
72
+ persist: true,
73
+ })
@@ -0,0 +1,3 @@
1
+ export * from './auth'
2
+ export * from './route'
3
+ export * from './tab'
@@ -0,0 +1,159 @@
1
+ import type { IMenu } from '../types'
2
+ import { defineStore } from 'pinia'
3
+ import { inject, Ref, ref } from 'vue'
4
+
5
+
6
+
7
+
8
+ /**
9
+ * use route store
10
+ * @param manageName manage name
11
+ * @returns route store
12
+ */
13
+ export function useRouteStore(manageName?: string) {
14
+ const manage = inject<Ref<string>>('dux.manage')
15
+ if (!manageName) {
16
+ manageName = manage?.value || ''
17
+ }
18
+
19
+ if (!manageName) {
20
+ throw new Error('manage not found')
21
+ }
22
+
23
+ const routeStore = createRouteStore(manageName)
24
+ return routeStore()
25
+
26
+ }
27
+
28
+ /**
29
+ * create route store
30
+ * @param manageName manage name
31
+ * @returns route store
32
+ */
33
+ export function createRouteStore(manageName: string) {
34
+ return defineStore(`routes-${manageName}`, () => {
35
+
36
+ const routes = ref<IMenu[]>([])
37
+
38
+ /**
39
+ * search route by path
40
+ * @param path route path
41
+ * @returns route object
42
+ */
43
+ const searchRoute = (path: string) => {
44
+ return routes.value?.find((item) => {
45
+ return item.path === path
46
+ })
47
+ }
48
+
49
+ /**
50
+ * search route by name
51
+ * @param name route name
52
+ * @returns route object
53
+ */
54
+ const searchRouteName = (name: string) => {
55
+ return routes.value?.find((item) => {
56
+ return item.name === name
57
+ })
58
+ }
59
+
60
+ /**
61
+ * append route
62
+ * @param data route object
63
+ */
64
+ const appendRoute = (data: IMenu) => {
65
+ routes.value?.push(data)
66
+ }
67
+
68
+ /**
69
+ * append routes
70
+ * @param data route objects
71
+ */
72
+ const appendRoutes = (data: IMenu[]) => {
73
+ routes.value = [...routes.value, ...data]
74
+ }
75
+
76
+ /**
77
+ * set routes
78
+ * @param data route objects
79
+ */
80
+ const setRoutes = (data: IMenu[]) => {
81
+ routes.value = data
82
+ }
83
+
84
+ /**
85
+ * get routes
86
+ * @returns route objects
87
+ */
88
+ const getRoutes = () => {
89
+ return routes.value
90
+ }
91
+
92
+ /**
93
+ * clear routes
94
+ */
95
+ const clearRoutes = () => {
96
+ routes.value = []
97
+ }
98
+
99
+ /**
100
+ * get index route
101
+ * @returns route object
102
+ */
103
+ const getIndexRoute = () => {
104
+ const topRoutes = routes.value
105
+ ?.filter(item => !item.parent && !item.name.includes('404') && !item.name.includes('403'))
106
+ ?.sort((a, b) => (a.sort || 0) - (b.sort || 0))
107
+
108
+ const findFirstValidRoute = (route: IMenu): IMenu | undefined => {
109
+ if (route.path) {
110
+ return route
111
+ }
112
+
113
+ const children = routes.value
114
+ ?.filter(item => item.parent === route.name)
115
+ ?.sort((a, b) => (a.sort || 0) - (b.sort || 0))
116
+
117
+ for (const child of children || []) {
118
+ const validRoute = findFirstValidRoute(child)
119
+ if (validRoute) {
120
+ return validRoute
121
+ }
122
+ }
123
+
124
+ return undefined
125
+ }
126
+
127
+ for (const route of topRoutes || []) {
128
+ const validRoute = findFirstValidRoute(route)
129
+ if (validRoute) {
130
+ return validRoute
131
+ }
132
+ }
133
+
134
+ return undefined
135
+ }
136
+
137
+
138
+ const routeInit = ref<boolean>(false)
139
+
140
+ const getRouteInit = () => {
141
+ const init = routeInit.value
142
+ routeInit.value = true
143
+ return init
144
+ }
145
+
146
+ return {
147
+ routes,
148
+ searchRoute,
149
+ searchRouteName,
150
+ appendRoute,
151
+ appendRoutes,
152
+ setRoutes,
153
+ getRoutes,
154
+ clearRoutes,
155
+ getIndexRoute,
156
+ getRouteInit,
157
+ }
158
+ })
159
+ }
@@ -0,0 +1,120 @@
1
+ import { defineStore } from 'pinia'
2
+ import { inject, Ref, ref } from 'vue'
3
+ import { IMenu } from '../types'
4
+
5
+
6
+ export function useTabStore(manageName?: string) {
7
+ const manage = inject<Ref<string>>('dux.manage')
8
+ if (!manageName) {
9
+ manageName = manage?.value || ''
10
+ }
11
+
12
+ if (!manageName) {
13
+ throw new Error('manage not found')
14
+ }
15
+
16
+ const tabStore = createTabStore(manageName)
17
+ return tabStore()
18
+ }
19
+
20
+ export function createTabStore(manageName: string) {
21
+ return defineStore(`tab-${manageName}`, () => {
22
+ const current = ref<string>()
23
+ const tabs = ref<IMenu[]>([])
24
+
25
+ const isTab = (path: string) => {
26
+ return tabs.value.some(tag => tag.path === path)
27
+ }
28
+ const addTab = (item: IMenu, cb?: (item: IMenu) => void) => {
29
+ if (!item.path) {
30
+ return
31
+ }
32
+ if (!tabs.value.some(tag => tag.path === item.path)) {
33
+ tabs.value.push(item)
34
+ cb?.(item)
35
+ }
36
+ current.value = item.path as string
37
+ }
38
+
39
+ const delTab = (path: string, cb?: (item: IMenu) => void) => {
40
+ const index = tabs.value.findIndex(t => t.path === path)
41
+ if (!index || tabs.value.length <= 1) {
42
+ return
43
+ }
44
+
45
+ const tab = tabs.value[index]
46
+ if (tab?.meta?.lock) {
47
+ return
48
+ }
49
+
50
+ const prev = tabs.value[index - 1]
51
+ const next = tabs.value[index + 1]
52
+
53
+ cb?.(prev || next)
54
+
55
+ setTimeout(() => {
56
+ tabs.value.splice(index, 1)
57
+ }, 0)
58
+ }
59
+
60
+ const delOther = (path: string, cb?: () => void) => {
61
+ tabs.value = tabs.value.filter(t => t.path === path || t.meta?.lock)
62
+ cb?.()
63
+ }
64
+
65
+ const delLeft = (path: string, cb?: () => void) => {
66
+ const index = tabs.value.findIndex(t => t.path === path)
67
+ if (index <= 0) {
68
+ return
69
+ }
70
+ tabs.value = [...tabs.value.slice(0, index).filter(t => t.meta?.lock), ...tabs.value.slice(index)]
71
+ cb?.()
72
+ }
73
+
74
+ const delRight = (path: string, cb?: () => void) => {
75
+ const index = tabs.value.findIndex(t => t.path === path)
76
+ if (index === -1 || index === tabs.value.length - 1) {
77
+ return
78
+ }
79
+ tabs.value = [...tabs.value.slice(0, index + 1), ...tabs.value.slice(index + 1).filter(t => t.meta?.lock)]
80
+ cb?.()
81
+ }
82
+
83
+ const lockTab = (path: string) => {
84
+ const index = tabs.value.findIndex(t => t.path === path)
85
+ if (index !== -1 && tabs.value[index]) {
86
+ if (!tabs.value[index].meta) {
87
+ tabs.value[index].meta = {}
88
+ }
89
+ tabs.value[index].meta.lock = !tabs.value[index].meta.lock
90
+ }
91
+ }
92
+
93
+ const changeTab = (path: string, cb?: (item: IMenu) => void) => {
94
+ current.value = path
95
+ const info = tabs.value.find(t => t.path === path)
96
+ if (info) {
97
+ cb?.(info)
98
+ }
99
+ }
100
+
101
+ const clearTab = () => {
102
+ current.value = undefined
103
+ tabs.value = []
104
+ }
105
+
106
+ return {
107
+ current,
108
+ tabs,
109
+ isTab,
110
+ addTab,
111
+ delTab,
112
+ changeTab,
113
+ delOther,
114
+ delLeft,
115
+ delRight,
116
+ lockTab,
117
+ clearTab,
118
+ }
119
+ })
120
+ }
@@ -0,0 +1,44 @@
1
+ import type { IManageHook } from '../hooks'
2
+ import type { IUserState } from '../stores/auth'
3
+
4
+ /**
5
+ * 认证提供者
6
+ * 为全局或管理端提供自定义认证服务
7
+ */
8
+ export interface IAuthProvider {
9
+ login: (params: any, manage: IManageHook) => Promise<IAuthLoginResponse>
10
+ check: (params?: any, manage?: IManageHook) => Promise<IAuthCheckResponse>
11
+ logout: (params?: any, manage?: IManageHook) => Promise<IAuthLogoutResponse>
12
+
13
+ register: (params: any, manage?: IManageHook) => Promise<IAuthLoginResponse>
14
+ forgotPassword: (params: any, manage?: IManageHook) => Promise<IAuthActionResponse>
15
+ updatePassword: (params: any, manage?: IManageHook) => Promise<IAuthActionResponse>
16
+
17
+ onError: (error?: any) => Promise<IAuthErrorResponse>
18
+ }
19
+
20
+ export interface IAuthActionResponse {
21
+ success: boolean
22
+ message?: string
23
+ redirectTo?: string
24
+ [key: string]: unknown
25
+ }
26
+
27
+ export interface IAuthLoginResponse extends IAuthActionResponse {
28
+ data?: IUserState
29
+ }
30
+
31
+ export interface IAuthCheckResponse extends IAuthActionResponse {
32
+ data?: IUserState
33
+ logout?: boolean
34
+ }
35
+
36
+ export interface IAuthLogoutResponse extends IAuthActionResponse {
37
+ logout?: boolean
38
+ }
39
+
40
+ export interface IAuthErrorResponse {
41
+ logout?: boolean
42
+ redirectTo?: string
43
+ error?: any
44
+ }
@@ -0,0 +1,49 @@
1
+ import type { RouteComponent, RouteRecordRaw } from 'vue-router'
2
+ import type { IAuthProvider } from './auth'
3
+ import type { IDataProvider } from './data'
4
+ import type { IManage } from './manage'
5
+ import type { IConfigTheme } from './theme'
6
+
7
+ /**
8
+ * 全局配置
9
+ */
10
+ export interface IConfig {
11
+ // 标题
12
+ title?: string
13
+ // 版权
14
+ copyright?: string
15
+ // 描述
16
+ description?: string
17
+ // 全局接口地址
18
+ apiUrl?: string
19
+ // 默认语言
20
+ lang?: string
21
+ // 扩展配置
22
+ extends?: Record<string, any>
23
+ // 默认管理端
24
+ defaultManage?: string
25
+ // 管理端提供者
26
+ manages?: IManage[]
27
+ // 全局认证提供者
28
+ authProvider?: IAuthProvider
29
+ // 全局数据提供者
30
+ dataProvider?: IDataProvider
31
+ // 全局布局配置
32
+ components?: IConfigComponent
33
+ // 全局路由配置
34
+ routes?: RouteRecordRaw[]
35
+ // 全局主题
36
+ theme?: IConfigTheme
37
+
38
+ [key: string]: any
39
+ }
40
+
41
+
42
+ export interface IConfigComponent {
43
+ authLayout?: RouteComponent // 认证布局
44
+ noAuthLayout?: RouteComponent // 未认证布局
45
+
46
+ notFound?: RouteComponent // 未找到布局
47
+ notAuthorized?: RouteComponent // 未授权布局
48
+ error?: RouteComponent // 错误布局
49
+ }