@pubinfo/core 2.0.0-rc.3 → 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 (97) hide show
  1. package/dist/{AppSetting-3wJKvibc.js → AppSetting-BI-oNc4e.js} +15 -15
  2. package/dist/{HCheckList.vue_vue_type_script_setup_true_lang-17EywJvs.js → HCheckList.vue_vue_type_script_setup_true_lang-BdLpkcoh.js} +1 -1
  3. package/dist/{HToggle-B-ZjSh6S.js → HToggle-DxdWLgp-.js} +1 -1
  4. package/dist/{PreferencesContent-xT4paU7N.js → PreferencesContent-CCYkZeCT.js} +4 -4
  5. package/dist/{SettingBreadcrumb-CYnO51Ek.js → SettingBreadcrumb-BTyfiy4k.js} +3 -3
  6. package/dist/{SettingCopyright-FOW5ObHK.js → SettingCopyright-g6UHi8pZ.js} +2 -2
  7. package/dist/{SettingEnableTransition-Q5cvubmF.js → SettingEnableTransition-Ci-5bhbR.js} +2 -2
  8. package/dist/{SettingHome-Df7-AlWB.js → SettingHome-K4Iel0Hr.js} +2 -2
  9. package/dist/{SettingMenu-BNAJ3el9.js → SettingMenu-BYLWzA5i.js} +3 -3
  10. package/dist/{SettingMode-LzlRsBL9.js → SettingMode-tRisyKtg.js} +1 -1
  11. package/dist/{SettingNavSearch-BA08vYuw.js → SettingNavSearch-CSM6mPf8.js} +2 -2
  12. package/dist/{SettingOther-BE8dDCYD.js → SettingOther-Bj5KF_vC.js} +2 -2
  13. package/dist/{SettingPage-D061yXCv.js → SettingPage-CFjmrVI7.js} +2 -2
  14. package/dist/{SettingTabbar-COwdPPKy.js → SettingTabbar-uFYiaZhK.js} +3 -3
  15. package/dist/{SettingThemes-BHaYERNp.js → SettingThemes-C-tMq9o5.js} +1 -1
  16. package/dist/{SettingToolbar-fSuzu6ND.js → SettingToolbar-BfDzijNU.js} +2 -2
  17. package/dist/{SettingTopbar-D7GgP0KB.js → SettingTopbar-DTDv4NXD.js} +3 -3
  18. package/dist/{SettingWidthMode-CNjzChe1.js → SettingWidthMode-PkiwrHe3.js} +1 -1
  19. package/dist/{TopThinMode-B-28sBJD.js → TopThinMode-BrvA8pV0.js} +1 -1
  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/components/ui/HSlideover.vue.d.ts +1 -1
  25. package/dist/built-in/layout-component/composables/useContext.d.ts +1 -1
  26. package/dist/built-in/layout-component/composables/useTitle.d.ts +1 -1
  27. package/dist/{colors-BIQSd520.js → colors-VoaDbOhe.js} +1 -1
  28. package/dist/core/interface.d.ts +14 -5
  29. package/dist/core/request.d.ts +2 -8
  30. package/dist/features/api/modules/auth/renzhengfuwu.d.ts +8 -8
  31. package/dist/features/api/modules/configData/heibaimingdanfuwu.d.ts +5 -5
  32. package/dist/features/api/modules/configData/xitongpeizhifuwu.d.ts +14 -14
  33. package/dist/features/api/modules/configData/zidifuwu.d.ts +10 -10
  34. package/dist/features/api/modules/rbac/gangweijiekou.d.ts +6 -6
  35. package/dist/features/api/modules/rbac/jiaosejiekou.d.ts +7 -7
  36. package/dist/features/api/modules/rbac/pubJiaosezukongzhiqi.d.ts +7 -7
  37. package/dist/features/api/modules/rbac/shujuquanxianzhubiaokongzhiqi.d.ts +9 -9
  38. package/dist/features/api/modules/rbac/yonghujiekou.d.ts +15 -15
  39. package/dist/features/api/modules/rbac/yonghushoucangbiaojiekou.d.ts +5 -5
  40. package/dist/features/api/modules/rbac/yonghuzuijinchangyongbiaojiekou.d.ts +4 -4
  41. package/dist/features/api/modules/rbac/ziyuanjiekou.d.ts +13 -13
  42. package/dist/features/api/modules/rbac/zuhuguanlijiekou.d.ts +5 -5
  43. package/dist/features/api/modules/rbac/zuzhijiaosebiaokongzhiqi.d.ts +4 -4
  44. package/dist/features/api/modules/rbac/zuzhijiekou.d.ts +9 -9
  45. package/dist/features/api/system/user.d.ts +4 -4
  46. package/dist/{index-YSjb6X1D.js → index-BSevJVD5.js} +4 -7
  47. package/dist/{index-Dlf6GQBd.js → index-BfGqLWFB.js} +4 -4
  48. package/dist/{index-DYMBkmAp.js → index-CYoFRwvw.js} +2 -2
  49. package/dist/{index-DNdH93AP.js → index-ConeY38N.js} +2 -2
  50. package/dist/{index-CPRiufg0.js → index-DV3hkzKA.js} +1 -1
  51. package/dist/{index-wxEEuQXu.js → index-Ddw98rJ5.js} +9 -9
  52. package/dist/{index-IscoZG-Y.js → index-DrC787X_.js} +2 -2
  53. package/dist/{index-WubcSL0v.js → index-Dv9ndBoi.js} +1 -1
  54. package/dist/{index-Beb7_0-E.js → index-IAYhIBQH.js} +16305 -16239
  55. package/dist/index.js +1 -1
  56. package/dist/{pick-D_XPbQHB.js → pick-vpv9EEvu.js} +1 -1
  57. package/dist/style.css +1 -1
  58. package/package.json +7 -7
  59. package/src/built-in/authentication/alova/helper.ts +158 -0
  60. package/src/built-in/authentication/alova/token.ts +122 -0
  61. package/src/built-in/authentication/helper.ts +7 -3
  62. package/src/built-in/authentication/index.ts +6 -20
  63. package/src/built-in/index.ts +0 -1
  64. package/src/built-in/layout-component/components/Header/TopMode/index.vue +3 -3
  65. package/src/built-in/layout-component/components/Menu/item.vue +3 -3
  66. package/src/built-in/layout-component/components/Sidebar/MainSidebar.vue +3 -3
  67. package/src/built-in/layout-component/components/Tools/SearchBar.vue +1 -3
  68. package/src/built-in/layout-component/components/Tools/SearchPanel.vue +12 -20
  69. package/src/built-in/layout-component/components/Tools/index.vue +8 -11
  70. package/src/built-in/layout-component/components/Topbar/Tabbar/MoreAction.vue +7 -10
  71. package/src/built-in/layout-component/components/Topbar/Tabbar/index.vue +10 -13
  72. package/src/built-in/layout-component/components/Topbar/Toolbar/Favorites.vue +4 -7
  73. package/src/built-in/layout-component/components/Topbar/Toolbar/index.vue +6 -6
  74. package/src/built-in/layout-component/composables/useContext.ts +1 -1
  75. package/src/built-in/layout-component/composables/useTitle.ts +8 -14
  76. package/src/built-in/layout-component/provider.ts +2 -2
  77. package/src/core/interface.ts +18 -5
  78. package/src/core/request.ts +35 -15
  79. package/src/features/router/systemRoutes.ts +0 -1
  80. package/src/features/stores/modules/favorites.ts +0 -1
  81. package/src/features/stores/modules/route.ts +2 -9
  82. package/src/features/stores/modules/tabbar.ts +0 -3
  83. package/src/features/stores/utils/routerHelper.ts +35 -4
  84. package/src/index.ts +0 -2
  85. package/types/vue-router.d.ts +0 -3
  86. package/dist/built-in/locales/helpler.d.ts +0 -594
  87. package/dist/built-in/locales/index.d.ts +0 -5
  88. package/dist/built-in/locales/lang/en.json.d.ts +0 -99
  89. package/dist/built-in/locales/lang/zh-cn.json.d.ts +0 -100
  90. package/dist/built-in/locales/lang/zh-tw.json.d.ts +0 -100
  91. package/dist/built-in/locales/ui.d.ts +0 -3
  92. package/src/built-in/locales/helpler.ts +0 -76
  93. package/src/built-in/locales/index.ts +0 -20
  94. package/src/built-in/locales/lang/en.json +0 -96
  95. package/src/built-in/locales/lang/zh-cn.json +0 -97
  96. package/src/built-in/locales/lang/zh-tw.json +0 -97
  97. package/src/built-in/locales/ui.ts +0 -3
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.3",
4
+ "version": "2.0.0-rc.4",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -22,13 +22,13 @@
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.3",
28
- "@pubinfo/vite": "2.0.0-rc.3"
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",
@@ -58,6 +58,7 @@
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
64
  "@pubinfo/openapi": "^0.9.0",
@@ -80,10 +81,9 @@
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.3",
86
- "@pubinfo/vite": "2.0.0-rc.3"
85
+ "@pubinfo/config": "2.0.0-rc.4",
86
+ "@pubinfo/vite": "2.0.0-rc.4"
87
87
  },
88
88
  "scripts": {
89
89
  "dev": "vite build -w -m watch",
@@ -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';
@@ -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"
@@ -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>
@@ -1,5 +1,4 @@
1
1
  <script setup lang="ts">
2
- import { useI18n } from 'vue-i18n';
3
2
  import IconamoonSearch from '~icons/iconamoon/search';
4
3
  import { useContext } from '../../composables/useContext';
5
4
  import { useGlobalSearch } from '../../composables/useGlobalSearch';
@@ -10,7 +9,6 @@ defineOptions({
10
9
 
11
10
  const { settingsStore } = useContext();
12
11
  const { toggle: toggleSearch } = useGlobalSearch();
13
- const { t } = useI18n();
14
12
 
15
13
  const searchComponentsClass = computed(() => {
16
14
  const componentsClass = {
@@ -33,7 +31,7 @@ const searchComponentsClass = computed(() => {
33
31
  @click="toggleSearch('menu')"
34
32
  >
35
33
  <IconamoonSearch text="14px" />
36
- <span class="text-sm transition ">{{ t('app.search.text') }}</span>
34
+ <span class="text-sm transition ">{{ '搜索' }}</span>
37
35
  <HKbd
38
36
  v-if="settingsStore.settings.navSearch.enableHotkeys"
39
37
  class="ml-2"
@@ -6,7 +6,6 @@ import { Dialog, DialogDescription, DialogPanel, TransitionChild, TransitionRoot
6
6
  import hotkeys from 'hotkeys-js';
7
7
  import { cloneDeep } from 'lodash-es';
8
8
  import { OverlayScrollbarsComponent } from 'overlayscrollbars-vue';
9
- import { useI18n } from 'vue-i18n';
10
9
  import AntDesignCaretDownFilled from '~icons/ant-design/caret-down-filled';
11
10
  import AntDesignCaretUpFilled from '~icons/ant-design/caret-up-filled';
12
11
  import EpSearch from '~icons/ep/search';
@@ -45,17 +44,14 @@ const transitionClass = computed(() => {
45
44
  };
46
45
  });
47
46
 
48
- const { t } = useI18n();
49
-
50
47
  const router = useRouter();
51
- const { settingsStore, routeStore, tabbarStore, generateI18nTitle } = useContext();
48
+ const { settingsStore, routeStore, tabbarStore, generateTitle } = useContext();
52
49
 
53
50
  type searchTypes = 'menu' | 'tab';
54
51
  interface listTypes {
55
52
  path: string
56
53
  icon?: string
57
54
  title?: string | (() => string)
58
- i18n?: string
59
55
  link?: string
60
56
  breadcrumb: any[]
61
57
  }
@@ -76,13 +72,13 @@ const resultList = computed(() => {
76
72
  let result = [];
77
73
  result = sourceList.value.filter((item) => {
78
74
  let flag = false;
79
- if (generateI18nTitle(item.i18n, item.title).toString().includes(searchInput.value)) {
75
+ if (generateTitle(item.title).toString().includes(searchInput.value)) {
80
76
  flag = true;
81
77
  }
82
78
  if (item.path.includes(searchInput.value)) {
83
79
  flag = true;
84
80
  }
85
- if (item.breadcrumb.some((b: { i18n: any, title: any }) => generateI18nTitle(b.i18n, b.title).toString().includes(searchInput.value))) {
81
+ if (item.breadcrumb.some((b: { title: any }) => generateTitle(b.title).toString().includes(searchInput.value))) {
86
82
  flag = true;
87
83
  }
88
84
  return flag;
@@ -155,27 +151,24 @@ function hasChildren(item: RouteRecordRaw) {
155
151
  }
156
152
  return flag;
157
153
  }
158
- function getSourceList(arr: RouteRecordRaw[], basePath?: string, icon?: string, breadcrumb?: { title?: string | (() => string), i18n?: string }[]) {
154
+ function getSourceList(arr: RouteRecordRaw[], basePath?: string, icon?: string, breadcrumb?: { title?: string | (() => string) }[]) {
159
155
  arr.forEach((item) => {
160
156
  if (item.meta?.sidebar !== false) {
161
157
  const breadcrumbTemp = cloneDeep(breadcrumb) || [];
162
158
  if (item.children && hasChildren(item)) {
163
159
  breadcrumbTemp.push({
164
160
  title: item.meta?.title,
165
- i18n: item.meta?.i18n,
166
161
  });
167
162
  getSourceList(item.children, resolveRoutePath(basePath, item.path), item.meta?.icon ?? icon, breadcrumbTemp);
168
163
  }
169
164
  else {
170
165
  breadcrumbTemp.push({
171
166
  title: item.meta?.title,
172
- i18n: item.meta?.i18n,
173
167
  });
174
168
  sourceList.value.push({
175
169
  path: resolveRoutePath(basePath, item.path),
176
170
  icon: item.meta?.icon ?? icon,
177
171
  title: item.meta?.title,
178
- i18n: item.meta?.i18n,
179
172
  link: item.meta?.link,
180
173
  breadcrumb: breadcrumbTemp,
181
174
  });
@@ -190,7 +183,6 @@ function getSourceListByTabs(arr: Tabbar.recordRaw[]) {
190
183
  icon: item.icon,
191
184
  title: item.title,
192
185
  path: item.fullPath,
193
- i18n: item.i18n,
194
186
  breadcrumb: [],
195
187
  });
196
188
  });
@@ -285,8 +277,8 @@ defineExpose({
285
277
  v-if="settingsStore.settings.tabbar.enable"
286
278
  v-model="searchType"
287
279
  :options="[
288
- { label: t('app.search.type.menu'), value: 'menu' },
289
- { label: t('app.search.type.tab'), value: 'tab' },
280
+ { label: '搜索导航菜单', value: 'menu' },
281
+ { label: '搜索标签页', value: 'tab' },
290
282
  ]"
291
283
  class="mb-4 flex!"
292
284
  @click.stop
@@ -298,7 +290,7 @@ defineExpose({
298
290
  <input
299
291
  ref="searchInputRef"
300
292
  v-model="searchInput"
301
- :placeholder="t('app.search.input')"
293
+ placeholder="搜索页面,支持标题、URL模糊查询"
302
294
  class="w-full border-0 rounded-md bg-transparent px-3 text-base text-dark dark:text-white focus:outline-none placeholder-stone-4 dark:placeholder-stone-5"
303
295
  @keydown.esc="toggle()"
304
296
  @keydown.up.prevent="keyUp"
@@ -332,10 +324,10 @@ defineExpose({
332
324
  :class="{ 'scale-120 text-ui-primary': index === actived }"
333
325
  />
334
326
  <div class="flex flex-1 flex-col gap-1 truncate px-4 py-3" border-l="~ solid stone-2 dark:stone-7">
335
- <div class="truncate text-base font-bold">{{ generateI18nTitle(item.i18n, item.title) }}</div>
327
+ <div class="truncate text-base font-bold">{{ generateTitle(item.title) }}</div>
336
328
  <Breadcrumb v-if="item.breadcrumb.length" class="truncate">
337
329
  <BreadcrumbItem v-for="(bc, bcIndex) in item.breadcrumb" :key="bcIndex" class="text-xs">
338
- {{ generateI18nTitle(bc.i18n, bc.title) }}
330
+ {{ generateTitle(bc.title) }}
339
331
  </BreadcrumbItem>
340
332
  </Breadcrumb>
341
333
  </div>
@@ -357,7 +349,7 @@ defineExpose({
357
349
  <HKbd>
358
350
  <IonMdReturnLeft text="14px" />
359
351
  </HKbd>
360
- <span>{{ t('app.search.enter') }}</span>
352
+ <span>{{ '访问' }}</span>
361
353
  </div>
362
354
  <div class="inline-flex items-center gap-1 text-xs">
363
355
  <HKbd>
@@ -366,14 +358,14 @@ defineExpose({
366
358
  <HKbd>
367
359
  <AntDesignCaretDownFilled text="14px" />
368
360
  </HKbd>
369
- <span>{{ t('app.search.up_down') }}</span>
361
+ <span>{{ '切换' }}</span>
370
362
  </div>
371
363
  </div>
372
364
  <div v-if="settingsStore.settings.navSearch.enableHotkeys" class="inline-flex items-center gap-1 text-xs">
373
365
  <HKbd>
374
366
  ESC
375
367
  </HKbd>
376
- <span>{{ t('app.search.esc') }}</span>
368
+ <span>{{ '退出' }}</span>
377
369
  </div>
378
370
  </div>
379
371
  </div>