@pubinfo/core 2.0.0-rc.2 → 2.0.0-rc.4

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 (133) hide show
  1. package/dist/{AppSetting-D2RJrc9O.js → AppSetting-BI-oNc4e.js} +19 -19
  2. package/dist/{HCheckList.vue_vue_type_script_setup_true_lang-DusVz35O.js → HCheckList.vue_vue_type_script_setup_true_lang-BdLpkcoh.js} +1 -1
  3. package/dist/{HToggle-DMcVgMVY.js → HToggle-DxdWLgp-.js} +1 -1
  4. package/dist/{PreferencesContent-Dtd9rtew.js → PreferencesContent-CCYkZeCT.js} +52 -52
  5. package/dist/{SettingBreadcrumb-QSCSviKM.js → SettingBreadcrumb-BTyfiy4k.js} +5 -5
  6. package/dist/{SettingCopyright-Dr5P6yfq.js → SettingCopyright-g6UHi8pZ.js} +2 -2
  7. package/dist/{SettingEnableTransition-DGiHEbCI.js → SettingEnableTransition-Ci-5bhbR.js} +12 -12
  8. package/dist/{SettingHome-CEPcBlds.js → SettingHome-K4Iel0Hr.js} +8 -8
  9. package/dist/{SettingMenu-BJdjnRA6.js → SettingMenu-BYLWzA5i.js} +14 -14
  10. package/dist/{SettingMode-BnuCHoEY.js → SettingMode-tRisyKtg.js} +3 -3
  11. package/dist/{SettingNavSearch-CiU4BmlU.js → SettingNavSearch-CSM6mPf8.js} +6 -6
  12. package/dist/{SettingOther-DTHjVlFe.js → SettingOther-Bj5KF_vC.js} +11 -11
  13. package/dist/{SettingPage-D75_Nf05.js → SettingPage-CFjmrVI7.js} +2 -2
  14. package/dist/{SettingTabbar-D48dzvgA.js → SettingTabbar-uFYiaZhK.js} +13 -13
  15. package/dist/{SettingThemes-D-8vTs5n.js → SettingThemes-C-tMq9o5.js} +12 -12
  16. package/dist/{SettingToolbar-DjIjm9V-.js → SettingToolbar-BfDzijNU.js} +10 -10
  17. package/dist/{SettingTopbar-Cg30OTH3.js → SettingTopbar-DTDv4NXD.js} +6 -6
  18. package/dist/{SettingWidthMode-BKV_7kb8.js → SettingWidthMode-PkiwrHe3.js} +11 -11
  19. package/dist/{TopThinMode-JFYsp_lJ.js → TopThinMode-BrvA8pV0.js} +3 -3
  20. package/dist/built-in/authentication/alova/helper.d.ts +34 -0
  21. package/dist/built-in/authentication/alova/token.d.ts +16 -0
  22. package/dist/built-in/authentication/helper.d.ts +10 -1
  23. package/dist/built-in/index.d.ts +0 -1
  24. package/dist/built-in/layout-component/Layout.vue.d.ts +1 -0
  25. package/dist/built-in/layout-component/components/Tools/Fullscreen.vue.d.ts +2 -0
  26. package/dist/built-in/layout-component/components/Tools/PageReload.vue.d.ts +2 -0
  27. package/dist/built-in/layout-component/components/Tools/SearchBar.vue.d.ts +2 -0
  28. package/dist/built-in/layout-component/components/Tools/index.vue.d.ts +47 -1
  29. package/dist/built-in/layout-component/components/Tools/interface.d.ts +26 -0
  30. package/dist/built-in/layout-component/components/ui/HDropdownMenu.vue.d.ts +2 -7
  31. package/dist/built-in/layout-component/components/ui/HSlideover.vue.d.ts +1 -1
  32. package/dist/built-in/layout-component/composables/useContext.d.ts +1 -1
  33. package/dist/built-in/layout-component/composables/useHotkey.d.ts +1 -5
  34. package/dist/built-in/layout-component/composables/useMainPage.d.ts +1 -1
  35. package/dist/built-in/layout-component/composables/useMenu.d.ts +1 -1
  36. package/dist/built-in/layout-component/composables/useTabbar.d.ts +1 -1
  37. package/dist/built-in/layout-component/composables/useTitle.d.ts +3 -2
  38. package/dist/built-in/layout-component/composables/useWatermark.d.ts +3 -1
  39. package/dist/built-in/layout-component/index.d.ts +9 -6
  40. package/dist/built-in/layout-component/utils/index.d.ts +0 -1
  41. package/dist/{colors-CODcBxrF.js → colors-VoaDbOhe.js} +1 -1
  42. package/dist/core/interface.d.ts +14 -5
  43. package/dist/core/request.d.ts +2 -8
  44. package/dist/features/api/modules/auth/renzhengfuwu.d.ts +8 -8
  45. package/dist/features/api/modules/configData/heibaimingdanfuwu.d.ts +5 -5
  46. package/dist/features/api/modules/configData/xitongpeizhifuwu.d.ts +14 -14
  47. package/dist/features/api/modules/configData/zidifuwu.d.ts +10 -10
  48. package/dist/features/api/modules/rbac/gangweijiekou.d.ts +6 -6
  49. package/dist/features/api/modules/rbac/jiaosejiekou.d.ts +7 -7
  50. package/dist/features/api/modules/rbac/pubJiaosezukongzhiqi.d.ts +7 -7
  51. package/dist/features/api/modules/rbac/shujuquanxianzhubiaokongzhiqi.d.ts +9 -9
  52. package/dist/features/api/modules/rbac/yonghujiekou.d.ts +15 -15
  53. package/dist/features/api/modules/rbac/yonghushoucangbiaojiekou.d.ts +5 -5
  54. package/dist/features/api/modules/rbac/yonghuzuijinchangyongbiaojiekou.d.ts +4 -4
  55. package/dist/features/api/modules/rbac/ziyuanjiekou.d.ts +13 -13
  56. package/dist/features/api/modules/rbac/zuhuguanlijiekou.d.ts +5 -5
  57. package/dist/features/api/modules/rbac/zuzhijiaosebiaokongzhiqi.d.ts +4 -4
  58. package/dist/features/api/modules/rbac/zuzhijiekou.d.ts +9 -9
  59. package/dist/features/api/system/user.d.ts +4 -4
  60. package/dist/{index-RT-QBzm0.js → index-BSevJVD5.js} +10 -15
  61. package/dist/{index-BVLkBCRY.js → index-BfGqLWFB.js} +6418 -6439
  62. package/dist/{index-DQn1WFMa.js → index-CYoFRwvw.js} +2 -2
  63. package/dist/{index-DmcblkoZ.js → index-ConeY38N.js} +13 -13
  64. package/dist/{index-BAoB7aoj.js → index-DV3hkzKA.js} +1 -1
  65. package/dist/{index-D4_xmL_A.js → index-Ddw98rJ5.js} +25 -25
  66. package/dist/{index-DvJr0paY.js → index-DrC787X_.js} +2 -2
  67. package/dist/{index-BROqFYXS.js → index-Dv9ndBoi.js} +1 -1
  68. package/dist/{index-Jd3PYkpj.js → index-IAYhIBQH.js} +16815 -16694
  69. package/dist/index.d.ts +4 -2
  70. package/dist/index.js +53 -55
  71. package/dist/{pick-BLJM77QN.js → pick-vpv9EEvu.js} +1 -1
  72. package/dist/style.css +1 -1
  73. package/package.json +11 -11
  74. package/src/built-in/authentication/alova/helper.ts +158 -0
  75. package/src/built-in/authentication/alova/token.ts +122 -0
  76. package/src/built-in/authentication/helper.ts +7 -3
  77. package/src/built-in/authentication/index.ts +6 -20
  78. package/src/built-in/index.ts +0 -1
  79. package/src/built-in/layout-component/Layout.vue +11 -22
  80. package/src/built-in/layout-component/components/Header/TopMode/index.vue +4 -4
  81. package/src/built-in/layout-component/components/Menu/item.vue +3 -3
  82. package/src/built-in/layout-component/components/Sidebar/MainSidebar.vue +4 -4
  83. package/src/built-in/layout-component/components/Sidebar/index.vue +1 -1
  84. package/src/built-in/layout-component/components/Tools/DarkModeToggle.vue +108 -0
  85. package/src/built-in/layout-component/components/Tools/Fullscreen.vue +24 -0
  86. package/src/built-in/layout-component/components/Tools/PageReload.vue +22 -0
  87. package/src/built-in/layout-component/components/Tools/SearchBar.vue +42 -0
  88. package/src/built-in/layout-component/components/Tools/{Search.vue → SearchPanel.vue} +13 -21
  89. package/src/built-in/layout-component/components/Tools/index.vue +71 -142
  90. package/src/built-in/layout-component/components/Tools/interface.ts +27 -0
  91. package/src/built-in/layout-component/components/Topbar/Tabbar/MoreAction.vue +9 -12
  92. package/src/built-in/layout-component/components/Topbar/Tabbar/index.vue +12 -15
  93. package/src/built-in/layout-component/components/Topbar/Toolbar/Favorites.vue +4 -7
  94. package/src/built-in/layout-component/components/Topbar/Toolbar/index.vue +6 -6
  95. package/src/built-in/layout-component/components/ui/HDropdownMenu.vue +19 -26
  96. package/src/built-in/layout-component/composables/useContext.ts +1 -1
  97. package/src/built-in/layout-component/composables/useGetComputedStyle.ts +2 -3
  98. package/src/built-in/layout-component/composables/useHotkey.ts +6 -10
  99. package/src/built-in/layout-component/composables/useMainPage.ts +5 -6
  100. package/src/built-in/layout-component/composables/useMenu.ts +3 -5
  101. package/src/built-in/layout-component/composables/useTabbar.ts +3 -5
  102. package/src/built-in/layout-component/composables/useTitle.ts +10 -17
  103. package/src/built-in/layout-component/composables/useWatermark.ts +25 -12
  104. package/src/built-in/layout-component/index.ts +21 -12
  105. package/src/built-in/layout-component/provider.ts +7 -3
  106. package/src/built-in/layout-component/utils/index.ts +0 -1
  107. package/src/built-in/settings/router.ts +5 -1
  108. package/src/core/interface.ts +18 -5
  109. package/src/core/request.ts +35 -15
  110. package/src/features/router/systemRoutes.ts +0 -1
  111. package/src/features/stores/modules/favorites.ts +0 -1
  112. package/src/features/stores/modules/route.ts +2 -9
  113. package/src/features/stores/modules/tabbar.ts +0 -3
  114. package/src/features/stores/utils/routerHelper.ts +38 -4
  115. package/src/index.ts +7 -11
  116. package/types/vue-router.d.ts +0 -3
  117. package/dist/built-in/layout-component/utils/eventBus.d.ts +0 -5
  118. package/dist/built-in/locales/helpler.d.ts +0 -594
  119. package/dist/built-in/locales/index.d.ts +0 -5
  120. package/dist/built-in/locales/lang/en.json.d.ts +0 -99
  121. package/dist/built-in/locales/lang/zh-cn.json.d.ts +0 -100
  122. package/dist/built-in/locales/lang/zh-tw.json.d.ts +0 -100
  123. package/dist/built-in/locales/ui.d.ts +0 -3
  124. package/src/built-in/layout-component/components/Tools/DayNightSwitch.vue +0 -70
  125. package/src/built-in/layout-component/utils/eventBus.ts +0 -8
  126. package/src/built-in/locales/helpler.ts +0 -76
  127. package/src/built-in/locales/index.ts +0 -20
  128. package/src/built-in/locales/lang/en.json +0 -96
  129. package/src/built-in/locales/lang/zh-cn.json +0 -97
  130. package/src/built-in/locales/lang/zh-tw.json +0 -97
  131. package/src/built-in/locales/ui.ts +0 -3
  132. /package/dist/built-in/layout-component/components/Tools/{DayNightSwitch.vue.d.ts → DarkModeToggle.vue.d.ts} +0 -0
  133. /package/dist/built-in/layout-component/components/Tools/{Search.vue.d.ts → SearchPanel.vue.d.ts} +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pubinfo/core",
3
3
  "type": "module",
4
- "version": "2.0.0-rc.2",
4
+ "version": "2.0.0-rc.4",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -22,17 +22,17 @@
22
22
  "alova": "^3.3.4",
23
23
  "pinia": "^3.0.3",
24
24
  "vue": "^3.5.17",
25
- "vue-i18n": "^10.0.7",
26
25
  "vue-router": "^4.5.1",
27
- "@pubinfo/config": "2.0.0-rc.2",
28
- "@pubinfo/vite": "2.0.0-rc.2"
26
+ "@pubinfo/config": "2.0.0-rc.4",
27
+ "@pubinfo/vite": "2.0.0-rc.4"
29
28
  },
30
29
  "dependencies": {
31
30
  "@alova/adapter-axios": "^2.0.16",
31
+ "@alova/shared": "^1.3.1",
32
32
  "@ant-design/icons-vue": "^7.0.1",
33
33
  "@headlessui/vue": "^1.7.23",
34
34
  "@imengyu/vue3-context-menu": "^1.5.1",
35
- "@pubinfo/pro-components": "^1.7.1",
35
+ "@pubinfo/pro-components": "^1.7.3",
36
36
  "@unocss/reset": "^66.4.2",
37
37
  "@vueuse/core": "^13.7.0",
38
38
  "@vueuse/integrations": "^13.5.0",
@@ -58,10 +58,11 @@
58
58
  "zxcvbn": "^4.4.2"
59
59
  },
60
60
  "devDependencies": {
61
+ "@alova/mock": "^2.0.17",
61
62
  "@iconify/json": "^2.2.354",
62
63
  "@iconify/vue": "^5.0.0",
63
- "@pubinfo/openapi": "^0.8.4",
64
- "@pubinfo/preset-openapi": "^0.8.4",
64
+ "@pubinfo/openapi": "^0.9.0",
65
+ "@pubinfo/preset-openapi": "^0.9.0",
65
66
  "@types/lodash-es": "^4.17.12",
66
67
  "@types/md5": "^2.3.5",
67
68
  "@types/nprogress": "^0.2.3",
@@ -80,13 +81,12 @@
80
81
  "vite": "^7.1.2",
81
82
  "vite-plugin-dts": "^4.5.4",
82
83
  "vue": "^3.5.17",
83
- "vue-i18n": "^10.0.7",
84
84
  "vue-router": "^4.5.1",
85
- "@pubinfo/config": "2.0.0-rc.2",
86
- "@pubinfo/vite": "2.0.0-rc.2"
85
+ "@pubinfo/config": "2.0.0-rc.4",
86
+ "@pubinfo/vite": "2.0.0-rc.4"
87
87
  },
88
88
  "scripts": {
89
- "dev": "vite build -w -m watch --sourcemap",
89
+ "dev": "vite build -w -m watch",
90
90
  "build": "vite build",
91
91
  "openapi": "pnpx @pubinfo/openapi generate"
92
92
  }
@@ -0,0 +1,158 @@
1
+ import type {
2
+ AlovaRequestAdapter,
3
+ Method,
4
+ RespondedHandler,
5
+ ResponseCompleteHandler,
6
+ ResponseErrorHandler,
7
+ StatesHook,
8
+ } from 'alova';
9
+ import type {
10
+ AlovaResponded,
11
+ MetaMatches,
12
+ ResponseAuthorizationInterceptor,
13
+ StateHookAdapter2AG,
14
+ } from 'alova/client';
15
+ import {
16
+ falseValue,
17
+ forEach,
18
+ instanceOf,
19
+ isFn,
20
+ isPlainObject,
21
+ len,
22
+ newInstance,
23
+ noop,
24
+ PromiseCls,
25
+ pushItem,
26
+ splice,
27
+ trueValue,
28
+ undefinedValue,
29
+ } from '@alova/shared';
30
+
31
+ export type PosibbleAuthMap
32
+ = | {
33
+ metaMatches?: MetaMatches
34
+ handler: any
35
+ }
36
+ | undefined;
37
+ export type WaitingRequestList = {
38
+ method: Method
39
+ resolve: () => void
40
+ }[];
41
+
42
+ export const defaultVisitorMeta = {
43
+ authRole: null,
44
+ };
45
+ export const defaultLoginMeta = {
46
+ authRole: 'login',
47
+ };
48
+ export const defaultLogoutMeta = {
49
+ authRole: 'logout',
50
+ };
51
+ export const defaultRefreshTokenMeta = {
52
+ authRole: 'refreshToken',
53
+ };
54
+ export function checkMethodRole({ meta }: Method, metaMatches: MetaMatches) {
55
+ if (isPlainObject(meta)) {
56
+ for (const key in meta) {
57
+ if (Object.prototype.hasOwnProperty.call(meta, key)) {
58
+ const matchedMetaItem = metaMatches[key];
59
+ if (instanceOf(matchedMetaItem, RegExp) ? matchedMetaItem.test(meta[key]) : meta[key] === matchedMetaItem) {
60
+ return trueValue;
61
+ }
62
+ }
63
+ }
64
+ }
65
+ return falseValue;
66
+ }
67
+ export function waitForTokenRefreshed(method: Method, waitingList: WaitingRequestList) {
68
+ return newInstance(PromiseCls, (resolve) => {
69
+ pushItem(waitingList, {
70
+ method,
71
+ resolve,
72
+ });
73
+ });
74
+ }
75
+ export function callHandlerIfMatchesMeta(method: Method,
76
+ authorizationInterceptor: ResponseAuthorizationInterceptor<AlovaRequestAdapter<any, any, any>> | undefined,
77
+ defaultMeta: MetaMatches,
78
+ response: any) {
79
+ if (checkMethodRole(method, (authorizationInterceptor as PosibbleAuthMap)?.metaMatches || defaultMeta)) {
80
+ const handler = isFn(authorizationInterceptor)
81
+ ? authorizationInterceptor
82
+ : isPlainObject(authorizationInterceptor) && isFn(authorizationInterceptor.handler)
83
+ ? authorizationInterceptor.handler
84
+ : noop;
85
+ return handler(response, method);
86
+ }
87
+ }
88
+ export async function refreshTokenIfExpired(method: Method,
89
+ waitingList: WaitingRequestList,
90
+ updateRefreshStatus: (status: boolean) => void,
91
+ handlerParams: any[],
92
+ refreshToken?: {
93
+ isExpired: (...args: any[]) => boolean | Promise<boolean>
94
+ handler: (...args: any[]) => Promise<void>
95
+ },
96
+ tokenRefreshing?: boolean) {
97
+ // When the number of handle params is greater than 2, it means that this function is called from the response, and the original interface needs to be requested again.
98
+ const fromResponse = len(handlerParams) >= 2;
99
+ let isExpired = refreshToken?.isExpired(...handlerParams);
100
+ // Compatible with synchronous and asynchronous functions
101
+ if (instanceOf(isExpired, PromiseCls)) {
102
+ isExpired = await isExpired;
103
+ }
104
+
105
+ if (isExpired) {
106
+ try {
107
+ // Make another judgment in the response to prevent multiple requests to refresh the token, intercept and wait for the token sent before the token refresh is completed.
108
+ let intentToRefreshToken = trueValue;
109
+ if (fromResponse && tokenRefreshing) {
110
+ intentToRefreshToken = falseValue; // The requests waiting here indicate that the token is being refreshed. When they pass, there is no need to refresh the token again.
111
+ await waitForTokenRefreshed(method, waitingList);
112
+ }
113
+
114
+ if (intentToRefreshToken) {
115
+ updateRefreshStatus(trueValue);
116
+ // Call refresh token
117
+ await refreshToken?.handler(...handlerParams);
118
+ updateRefreshStatus(falseValue);
119
+ // After the token refresh is completed, the requests in the waiting list are notified.
120
+ forEach(waitingList, ({ resolve }) => resolve());
121
+ }
122
+ if (fromResponse) {
123
+ // Because the original interface is being requested again, superposition with the previous request will result in repeated calls to transform, so it is necessary to leave transform empty to remove one call.
124
+ const { config } = method;
125
+ const methodTransformData = config.transform;
126
+ config.transform = undefinedValue;
127
+ const resentData = await method;
128
+ config.transform = methodTransformData;
129
+ return resentData;
130
+ }
131
+ }
132
+ finally {
133
+ updateRefreshStatus(falseValue);
134
+ splice(waitingList, 0, len(waitingList)); // Clear waiting list
135
+ }
136
+ }
137
+ }
138
+
139
+ export function onResponded2Record<SH extends StatesHook<any>, RA extends AlovaRequestAdapter<any, any, any>>(onRespondedHandlers?: AlovaResponded<SH, RA>) {
140
+ type AG = StateHookAdapter2AG<SH, RA>;
141
+ let successHandler: RespondedHandler<AG> | undefined = undefinedValue;
142
+ let errorHandler: ResponseErrorHandler<AG> | undefined = undefinedValue;
143
+ let onCompleteHandler: ResponseCompleteHandler<AG> | undefined = undefinedValue;
144
+ if (isFn(onRespondedHandlers)) {
145
+ successHandler = onRespondedHandlers;
146
+ }
147
+ else if (isPlainObject(onRespondedHandlers)) {
148
+ const { onSuccess, onError, onComplete } = onRespondedHandlers;
149
+ successHandler = isFn(onSuccess) ? onSuccess : successHandler;
150
+ errorHandler = isFn(onError) ? onError : errorHandler;
151
+ onCompleteHandler = isFn(onComplete) ? onComplete : onCompleteHandler;
152
+ }
153
+ return {
154
+ onSuccess: successHandler,
155
+ onError: errorHandler,
156
+ onComplete: onCompleteHandler,
157
+ };
158
+ }
@@ -0,0 +1,122 @@
1
+ import type { AlovaRequestAdapter, Method, StatesHook } from 'alova';
2
+ import type {
3
+ AlovaRequestAdapterUnified,
4
+ BeforeRequestType,
5
+ ServerTokenAuthenticationOptions,
6
+ } from 'alova/client';
7
+ import type { FetchRequestAdapter } from 'alova/fetch';
8
+ import type {
9
+ PosibbleAuthMap,
10
+ WaitingRequestList } from './helper';
11
+ import { $self, falseValue, noop } from '@alova/shared';
12
+ import {
13
+ callHandlerIfMatchesMeta,
14
+ checkMethodRole,
15
+ defaultLoginMeta,
16
+ defaultLogoutMeta,
17
+ defaultRefreshTokenMeta,
18
+ defaultVisitorMeta,
19
+ refreshTokenIfExpired,
20
+ waitForTokenRefreshed,
21
+ } from './helper';
22
+
23
+ /**
24
+ * Create a server-side token authentication interceptor
25
+ * @returns token authentication interceptor function
26
+ */
27
+ export function createServerTokenAuthentication<
28
+ SH extends StatesHook<any>,
29
+ RA extends
30
+ | AlovaRequestAdapter<any, any, any>
31
+ | ((...args: any[]) => AlovaRequestAdapter<any, any, any>) = FetchRequestAdapter,
32
+ >({
33
+ visitorMeta,
34
+ login,
35
+ logout,
36
+ refreshTokenOnSuccess,
37
+ refreshTokenOnError,
38
+ assignToken = noop,
39
+ }: ServerTokenAuthenticationOptions<AlovaRequestAdapterUnified<RA>>) {
40
+ let tokenRefreshing = falseValue;
41
+ const waitingList: WaitingRequestList = [];
42
+
43
+ const onAuthRequired: BeforeRequestType<SH, AlovaRequestAdapterUnified<RA>> = onBeforeRequest => async (method) => {
44
+ const isVisitorRole = checkMethodRole(method, visitorMeta || defaultVisitorMeta);
45
+ const isLoginRole = checkMethodRole(method, (login as PosibbleAuthMap)?.metaMatches || defaultLoginMeta);
46
+ // Ignored, login, and token refresh requests do not perform token authentication.
47
+ if (
48
+ !isVisitorRole
49
+ && !isLoginRole
50
+ && !checkMethodRole(method, (refreshTokenOnSuccess as PosibbleAuthMap)?.metaMatches || defaultRefreshTokenMeta)
51
+ && !checkMethodRole(method, (refreshTokenOnError as PosibbleAuthMap)?.metaMatches || defaultRefreshTokenMeta)
52
+ ) {
53
+ // If the token is being refreshed, wait for the refresh to complete before sending a request.
54
+ if (tokenRefreshing) {
55
+ await waitForTokenRefreshed(method, waitingList);
56
+ }
57
+ }
58
+ if (!isVisitorRole && !isLoginRole) {
59
+ await assignToken(method);
60
+ }
61
+ return onBeforeRequest?.(method);
62
+ };
63
+
64
+ const onResponseRefreshToken = () => {
65
+ return {
66
+ onSuccess: async (response: any, method: Method, stop: any) => {
67
+ if (
68
+ !checkMethodRole(method, visitorMeta || defaultVisitorMeta)
69
+ && !checkMethodRole(method, (login as PosibbleAuthMap)?.metaMatches || defaultLoginMeta)
70
+ && !checkMethodRole(method, (refreshTokenOnSuccess as PosibbleAuthMap)?.metaMatches || defaultRefreshTokenMeta)
71
+ ) {
72
+ const dataResent = await refreshTokenIfExpired(
73
+ method,
74
+ waitingList,
75
+ (refreshing) => {
76
+ tokenRefreshing = refreshing;
77
+ },
78
+ [response, method],
79
+ refreshTokenOnSuccess,
80
+ tokenRefreshing,
81
+ );
82
+ if (dataResent) {
83
+ stop();
84
+ return dataResent;
85
+ }
86
+ }
87
+
88
+ await callHandlerIfMatchesMeta(method, login, defaultLoginMeta, response);
89
+ await callHandlerIfMatchesMeta(method, logout, defaultLogoutMeta, response);
90
+ return $self(response);
91
+ },
92
+ onError: async (error: any, method: Method) => {
93
+ if (
94
+ !checkMethodRole(method, visitorMeta || defaultVisitorMeta)
95
+ && !checkMethodRole(method, (login as PosibbleAuthMap)?.metaMatches || defaultLoginMeta)
96
+ && !checkMethodRole(method, (refreshTokenOnError as PosibbleAuthMap)?.metaMatches || defaultRefreshTokenMeta)
97
+ ) {
98
+ const dataResent = await refreshTokenIfExpired(
99
+ method,
100
+ waitingList,
101
+ (refreshing) => {
102
+ tokenRefreshing = refreshing;
103
+ },
104
+ [error, method],
105
+ refreshTokenOnError,
106
+ tokenRefreshing,
107
+ );
108
+ if (dataResent) {
109
+ return dataResent;
110
+ }
111
+ }
112
+ return noop;
113
+ },
114
+ };
115
+ };
116
+
117
+ return {
118
+ waitingList,
119
+ onAuthRequired,
120
+ onResponseRefreshToken,
121
+ };
122
+ }
@@ -1,13 +1,16 @@
1
- import type { axiosRequestAdapter } from '@alova/adapter-axios';
1
+ import type { AxiosRequestAdapter, axiosRequestAdapter } from '@alova/adapter-axios';
2
+ import type { AlovaRequestAdapterUnified, ServerTokenAuthenticationOptions } from 'alova/client';
2
3
  import type VueHook from 'alova/vue';
3
4
  import type { AxiosResponse } from 'axios';
4
5
  import type { RequestResult } from './interface';
5
- import { createServerTokenAuthentication } from 'alova/client';
6
6
  import { postAuthTokenRefresh } from '@/features/api/modules/auth';
7
7
  import { useUserStore } from '@/features/stores';
8
+ import { createServerTokenAuthentication } from './alova/token';
8
9
  import { RESPONSE_CODE } from './enum';
9
10
 
10
- export function createTokenAuthentication() {
11
+ export function createTokenAuthentication(
12
+ options: ServerTokenAuthenticationOptions<AlovaRequestAdapterUnified<AxiosRequestAdapter>> = {},
13
+ ) {
11
14
  return createServerTokenAuthentication<typeof VueHook, typeof axiosRequestAdapter>({
12
15
  /**
13
16
  * 给权限接口添加Authorization
@@ -51,5 +54,6 @@ export function createTokenAuthentication() {
51
54
  userStore.setToken(accessToken, refreshToken);
52
55
  },
53
56
  },
57
+ ...options,
54
58
  });
55
59
  }
@@ -1,5 +1,5 @@
1
1
  import type { ModuleOptions } from '@/core';
2
- // import { createTokenAuthentication } from './helper';
2
+ import { createTokenAuthentication } from './helper';
3
3
  import { createRouterGuard } from './router';
4
4
 
5
5
  /**
@@ -8,21 +8,7 @@ import { createRouterGuard } from './router';
8
8
  * 双 token 校验,确认用户身份,注册修改密码和切换组织页面
9
9
  */
10
10
  export function Authentication(): ModuleOptions {
11
- // TODO hooks 的形式注册 alova 的 Token 认证拦截器,
12
- // Token 过期时的请求,在刷新完 Token 后虽然会重新请求,但是过期请求还是会继续抛出错误。
13
- // 若是用如下形式注册,则没有问题:
14
- // const alova = createAlova({
15
- // beforeRequest: onAuthRequired(method => {
16
- // }),
17
- // responded: onResponseRefreshToken({
18
- // onSuccess(response, method) {
19
- // },
20
- // onError(error, method) {
21
- // },
22
- // })
23
- // });
24
-
25
- // const { onAuthRequired, onResponseRefreshToken } = createTokenAuthentication();
11
+ const { onAuthRequired, onResponseRefreshToken } = createTokenAuthentication();
26
12
 
27
13
  return {
28
14
  name: 'built-in:authentication',
@@ -30,10 +16,10 @@ export function Authentication(): ModuleOptions {
30
16
  const { router } = ctx;
31
17
  createRouterGuard(router);
32
18
  },
33
- // hooks: {
34
- // 'http:request': onAuthRequired(),
35
- // 'http:response': onResponseRefreshToken(),
36
- // },
19
+ hooks: {
20
+ 'http:request': onAuthRequired(),
21
+ 'http:response': onResponseRefreshToken(),
22
+ },
37
23
  };
38
24
  }
39
25
 
@@ -1,7 +1,6 @@
1
1
  export * from './authentication';
2
2
  export * from './authorization';
3
3
  export * from './layout-component';
4
- export * from './locales';
5
4
  export * from './n-progress';
6
5
  export * from './pinia-plugin';
7
6
  export * from './pre-access';
@@ -4,30 +4,23 @@ import BackTop from './components/BackTop/index.vue';
4
4
  import LayoutContent from './components/Content/index.vue';
5
5
  import Copyright from './components/Copyright/index.vue';
6
6
  import LayoutHeader from './components/Header/index.vue';
7
-
8
7
  import SettingBar from './components/SettingBar/index.vue';
9
- // import Sidebar from './components/Sidebar/index.vue';
10
- import MainSidebar from './components/Sidebar/MainSidebar.vue';
11
- import SubSidebar from './components/Sidebar/SubSidebar.vue';
12
- import Topbar from './components/Topbar/index.vue';
8
+ import LayoutSidebar from './components/Sidebar/index.vue';
9
+ import LayoutTopbar from './components/Topbar/index.vue';
10
+
13
11
  import { useContext } from './composables/useContext';
14
12
  import { useGetSidebarActualWidth } from './composables/useGetComputedStyle';
15
13
  import { useHotkey } from './composables/useHotkey';
16
- import useWatermark from './composables/useWatermark';
14
+ import { useWatermark } from './composables/useWatermark';
17
15
 
18
16
  defineOptions({
19
17
  name: 'Layout',
20
18
  });
21
19
 
22
20
  const routeInfo = useRoute();
23
- const { settingsStore, menuStore } = useContext();
21
+ const { settingsStore } = useContext();
24
22
  const { mainSidebarActualWidth, subSidebarActualWidth } = useGetSidebarActualWidth();
25
-
26
- useHotkey({
27
- settingsStore,
28
- menuStore,
29
- });
30
-
23
+ useHotkey();
31
24
  useWatermark();
32
25
 
33
26
  watch(() => settingsStore.settings.menu.subMenuCollapse, (val) => {
@@ -68,13 +61,9 @@ watch(() => routeInfo.path, () => {
68
61
  class="sidebar-container"
69
62
  :class="{ show: settingsStore.mode === 'mobile' && !settingsStore.settings.menu.subMenuCollapse }"
70
63
  >
71
- <!-- TODO 这种写法会导致侧边栏模式的布局下,有样式问题 -->
72
- <!-- <slot name="sidebar">
73
- <Sidebar />
74
- </slot> -->
75
-
76
- <MainSidebar />
77
- <SubSidebar />
64
+ <slot name="sidebar">
65
+ <LayoutSidebar />
66
+ </slot>
78
67
  </div>
79
68
 
80
69
  <div
@@ -85,7 +74,7 @@ watch(() => routeInfo.path, () => {
85
74
 
86
75
  <div class="main-container" :style="{ 'padding-bottom': routeInfo.meta.paddingBottom }">
87
76
  <slot name="topbar">
88
- <Topbar />
77
+ <LayoutTopbar />
89
78
  </slot>
90
79
 
91
80
  <div class="main">
@@ -213,7 +202,7 @@ watch(() => routeInfo.path, () => {
213
202
  --at-apply: visible op-100;
214
203
  }
215
204
 
216
- .wrapper .main-sidebar-container:not(.main-sidebar-leave-active) + .sub-sidebar-container {
205
+ .wrapper ::v-deep(.main-sidebar-container:not(.main-sidebar-leave-active) + .sub-sidebar-container) {
217
206
  --at-apply: left-[--g-main-sidebar-width];
218
207
  }
219
208
 
@@ -4,7 +4,7 @@ import { useElementSize } from '@vueuse/core';
4
4
  import SolarWidget5BoldDuotone from '~icons/solar/widget-5-bold-duotone';
5
5
  import { PubinfoIcon } from '@/features/components';
6
6
  import { useContext } from '../../../composables/useContext';
7
- import useMenu from '../../../composables/useMenu';
7
+ import { useMenu } from '../../../composables/useMenu';
8
8
  import More from './More.vue';
9
9
  import NotCursor from './NotCursor.vue';
10
10
 
@@ -12,7 +12,7 @@ defineOptions({
12
12
  name: 'TopMode',
13
13
  });
14
14
 
15
- const { settingsStore, menuStore, generateI18nTitle } = useContext();
15
+ const { settingsStore, menuStore, generateTitle } = useContext();
16
16
  const { switchTo } = useMenu();
17
17
 
18
18
  function iconName(isActive: boolean, icon?: string, activeIcon?: string) {
@@ -113,7 +113,7 @@ onMounted(() => {
113
113
  'text-[var(--g-header-menu-active-color)]! bg-[var(--g-header-menu-active-bg)]!': index === menuStore.actived,
114
114
  'rounded-2': settingsStore.settings.menu.isRounded,
115
115
  }"
116
- :title="generateI18nTitle(item.meta?.i18n, item.meta?.title)"
116
+ :title="generateTitle(item.meta?.title)"
117
117
  @click="switchTo(index, item)"
118
118
  >
119
119
  <div class="flex flex-row flex-1 items-center justify-center px-8px">
@@ -124,7 +124,7 @@ onMounted(() => {
124
124
  class="menu-item-container-icon transition-transform group-hover:scale-120 mr-5px"
125
125
  />
126
126
  <span class="w-full flex-1 truncate text-center text-sm transition-height transition-opacity transition-width">
127
- {{ generateI18nTitle(item.meta?.i18n, item.meta?.title) }}
127
+ {{ generateTitle(item.meta?.title) }}
128
128
  </span>
129
129
  </div>
130
130
  </div>
@@ -18,7 +18,7 @@ const props = withDefaults(
18
18
  );
19
19
 
20
20
  const rootMenu = inject(rootMenuInjectionKey)!;
21
- const { generateI18nTitle } = useContext();
21
+ const { generateTitle } = useContext();
22
22
 
23
23
  const itemRef = ref<HTMLElement>();
24
24
 
@@ -78,7 +78,7 @@ defineExpose({
78
78
  'px-2!': rootMenu.isMenuPopup && level === 0,
79
79
  'py-3!': rootMenu.props.rounded && rootMenu.isMenuPopup && level !== 0,
80
80
  }"
81
- :title="generateI18nTitle(item.meta?.i18n, item.meta?.title)"
81
+ :title="generateTitle(item.meta?.title)"
82
82
  >
83
83
  <div
84
84
  class="menu-item-container-layout inline-flex flex-1 items-center justify-center gap-[12px]"
@@ -106,7 +106,7 @@ defineExpose({
106
106
  'system-point': icon === 'system-point' && isItemActive,
107
107
  }"
108
108
  >
109
- {{ generateI18nTitle(item.meta?.i18n, item.meta?.title) }}
109
+ {{ generateTitle(item.meta?.title) }}
110
110
  </span>
111
111
  <HBadge
112
112
  v-if="item.meta?.badge"
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { PubinfoIcon } from '@/features/components';
3
3
  import { useContext } from '../../composables/useContext';
4
- import useMenu from '../../composables/useMenu';
4
+ import { useMenu } from '../../composables/useMenu';
5
5
  import Logo from '../Logo/index.vue';
6
6
  import Menu from '../Menu/index.vue';
7
7
 
@@ -11,7 +11,7 @@ defineOptions({
11
11
 
12
12
  const route = useRoute();
13
13
 
14
- const { settingsStore, menuStore, generateI18nTitle } = useContext();
14
+ const { settingsStore, menuStore, generateTitle } = useContext();
15
15
  const { switchTo } = useMenu();
16
16
 
17
17
  function iconName(isActive: boolean, icon?: string, activeIcon?: string) {
@@ -50,7 +50,7 @@ function iconName(isActive: boolean, icon?: string, activeIcon?: string) {
50
50
  'text-[var(--g-main-sidebar-menu-active-color)]! bg-[var(--g-main-sidebar-menu-active-bg)]!': index === menuStore.actived,
51
51
  'rounded-2': settingsStore.settings.menu.isRounded,
52
52
  }"
53
- :title="generateI18nTitle(item.meta?.i18n, item.meta?.title)"
53
+ :title="generateTitle(item.meta?.title)"
54
54
  @click="switchTo(index, item)"
55
55
  >
56
56
  <div class="w-full inline-flex flex-1 flex-col items-center justify-center gap-[2px]">
@@ -62,7 +62,7 @@ function iconName(isActive: boolean, icon?: string, activeIcon?: string) {
62
62
  />
63
63
  <!-- 不需要title? -->
64
64
  <!-- <span class="w-full flex-1 truncate text-center text-sm transition-height transition-opacity transition-width">
65
- {{ generateI18nTitle(item.meta?.i18n, item.meta?.title) }}
65
+ {{ generateTitle(item.meta?.title) }}
66
66
  </span> -->
67
67
  </div>
68
68
  </div>
@@ -3,7 +3,7 @@ import MainSidebar from './MainSidebar.vue';
3
3
  import SubSidebar from './SubSidebar.vue';
4
4
 
5
5
  defineOptions({
6
- name: 'Sidebar',
6
+ name: 'LayoutSidebar',
7
7
  });
8
8
  </script>
9
9