generator-mico-cli 0.1.29 → 0.2.2-8.beta.1
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/README.md +199 -15
- package/bin/mico.js +232 -27
- package/generators/micro-react/index.js +200 -18
- package/generators/micro-react/meta.json +13 -0
- package/generators/micro-react/templates/.commitlintrc.js +1 -0
- package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +14 -4
- package/generators/micro-react/templates/.cursor/rules/cicd-deploy.mdc +10 -8
- package/generators/micro-react/templates/.cursor/rules/coding-conventions.mdc +1 -1
- package/generators/micro-react/templates/.cursor/rules/development-guide.mdc +3 -4
- package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +38 -31
- package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +7 -4
- package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +10 -12
- package/generators/micro-react/templates/.eslintrc.js +25 -1
- package/generators/micro-react/templates/AGENTS.md +5 -2
- package/generators/micro-react/templates/CICD/before_build.sh +76 -0
- package/generators/micro-react/templates/CICD/start_dev.sh +27 -3
- package/generators/micro-react/templates/CICD/start_prod.sh +26 -3
- package/generators/micro-react/templates/CICD/start_test.sh +28 -3
- package/generators/micro-react/templates/CICD/wangsu_fresh_dev.sh +4 -4
- package/generators/micro-react/templates/CICD/wangsu_fresh_prod.sh +4 -4
- package/generators/micro-react/templates/CICD/wangsu_fresh_test.sh +4 -4
- package/generators/micro-react/templates/CLAUDE.md +16 -9
- package/generators/micro-react/templates/README.md +42 -4
- package/generators/micro-react/templates/_gitignore +4 -0
- package/generators/micro-react/templates/_npmrc +4 -0
- package/generators/micro-react/templates/apps/layout/config/config.dev.ts +33 -17
- package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +24 -29
- package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +25 -6
- package/generators/micro-react/templates/apps/layout/config/config.prod.ts +16 -7
- package/generators/micro-react/templates/apps/layout/config/config.ts +27 -4
- package/generators/micro-react/templates/apps/layout/config/routes.ts +10 -5
- package/generators/micro-react/templates/apps/layout/docs/arch-/346/227/245/345/277/227/344/270/216/345/270/270/351/207/217.md +2 -2
- package/generators/micro-react/templates/apps/layout/docs/arch-/350/257/267/346/261/202/346/250/241/345/235/227.md +1 -1
- package/generators/micro-react/templates/apps/layout/docs/common-intl.md +372 -0
- package/generators/micro-react/templates/apps/layout/docs/feat-/346/236/204/345/273/272define/344/270/216/345/205/215/350/256/244/350/257/201/345/210/235/345/247/213/346/200/201.md +44 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-404/351/241/265/351/235/242.md +103 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/344/270/273/351/242/230/350/211/262/345/210/207/346/215/242.md +22 -26
- package/generators/micro-react/templates/apps/layout/docs/feature-/345/276/256/345/211/215/347/253/257/346/250/241/345/274/217.md +185 -28
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/217/234/345/215/225/346/235/203/351/231/220/346/216/247/345/210/266.md +420 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/267/257/347/224/261/344/270/216/350/217/234/345/215/225/350/247/243/350/200/246.md +179 -0
- package/generators/micro-react/templates/apps/layout/docs/fix-SSO/346/227/240/351/231/220/351/207/215/345/256/232/345/220/221.md +88 -0
- package/generators/micro-react/templates/apps/layout/docs/utils-timezone.md +324 -0
- package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
- package/generators/micro-react/templates/apps/layout/mock/menus.ts +114 -4
- package/generators/micro-react/templates/apps/layout/mock/pages.ts +86 -0
- package/generators/micro-react/templates/apps/layout/package.json +7 -4
- package/generators/micro-react/templates/apps/layout/src/app.tsx +122 -83
- package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +3 -0
- package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +177 -0
- package/generators/micro-react/templates/apps/layout/src/common/locale.ts +22 -17
- package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +283 -28
- package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +69 -5
- package/generators/micro-react/templates/apps/layout/src/common/micro/index.ts +34 -0
- package/generators/micro-react/templates/apps/layout/src/common/micro-prefetch.ts +109 -0
- package/generators/micro-react/templates/apps/layout/src/common/portal-data.ts +45 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +72 -10
- package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +2 -2
- package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +31 -3
- package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +29 -11
- package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +23 -8
- package/generators/micro-react/templates/apps/layout/src/common/route-guard.ts +345 -0
- package/generators/micro-react/templates/apps/layout/src/common/theme.ts +2 -4
- package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +3 -4
- package/generators/micro-react/templates/apps/layout/src/common/upload/types.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/common/uploadFiles.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +8 -3
- package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +25 -8
- package/generators/micro-react/templates/apps/layout/src/components/HeaderDropdown/index.tsx +20 -0
- package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +5 -6
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +21 -6
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +83 -107
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/micro-app-manager.ts +569 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +383 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/avatar-dropdown.less +35 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/index.ts +2 -0
- package/generators/micro-react/templates/apps/layout/src/constants/index.ts +170 -6
- package/generators/micro-react/templates/apps/layout/src/global.less +19 -6
- package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +3 -2
- package/generators/micro-react/templates/apps/layout/src/hooks/useRoutePermissionRefresh.ts +72 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +3 -1
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +10 -55
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +34 -4
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +33 -9
- package/generators/micro-react/templates/apps/layout/src/layouts/index.less +84 -13
- package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +178 -47
- package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +12 -0
- package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +12 -0
- package/generators/micro-react/templates/apps/layout/src/pages/403/index.tsx +34 -0
- package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +78 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +3 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.tsx +7 -1
- package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.less +1 -1
- package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.tsx +9 -5
- package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +1 -1
- package/generators/micro-react/templates/apps/layout/src/services/config/index.ts +63 -0
- package/generators/micro-react/templates/apps/layout/src/services/config/type.ts +30 -0
- package/generators/micro-react/templates/apps/layout/src/services/user.ts +29 -2
- package/generators/micro-react/templates/apps/layout/tailwind.config.js +3 -0
- package/generators/micro-react/templates/deployDesc.md +3 -3
- package/generators/micro-react/templates/dev.preset.json +14 -0
- package/generators/micro-react/templates/docs/dev-preset.md +130 -0
- package/generators/micro-react/templates/package.json +21 -6
- package/generators/micro-react/templates/packages/common-intl/README.md +427 -0
- package/generators/micro-react/templates/packages/common-intl/package.json +34 -0
- package/generators/micro-react/templates/packages/common-intl/src/index.ts +7 -0
- package/generators/micro-react/templates/packages/common-intl/src/indexedDBUtils.ts +51 -0
- package/generators/micro-react/templates/packages/common-intl/src/intl.ts +50 -0
- package/generators/micro-react/templates/packages/common-intl/src/utils.ts +482 -0
- package/generators/micro-react/templates/packages/common-intl/tsconfig.json +22 -0
- package/generators/micro-react/templates/packages/common-intl/vite.config.ts +25 -0
- package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +45 -0
- package/generators/micro-react/templates/scripts/collect-dist.js +10 -0
- package/generators/micro-react/templates/scripts/dev-preset.js +265 -0
- package/generators/micro-react/templates/scripts/dev-preset.schema.json +39 -0
- package/generators/micro-react/templates/turbo.json +4 -1
- package/generators/subapp-react/index.js +326 -40
- package/generators/subapp-react/meta.json +10 -0
- package/generators/subapp-react/templates/homepage/.env +2 -1
- package/generators/subapp-react/templates/homepage/README.md +3 -3
- package/generators/subapp-react/templates/homepage/config/config.dev.ts +14 -7
- package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +16 -5
- package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +16 -5
- package/generators/subapp-react/templates/homepage/config/config.prod.ts +14 -5
- package/generators/subapp-react/templates/homepage/config/config.ts +27 -0
- package/generators/subapp-react/templates/homepage/config/routes.ts +2 -2
- package/generators/subapp-react/templates/homepage/mock/api.mock.ts +2 -2
- package/generators/subapp-react/templates/homepage/package.json +7 -4
- package/generators/subapp-react/templates/homepage/src/app.tsx +18 -27
- package/generators/subapp-react/templates/homepage/src/common/request.ts +29 -2
- package/generators/subapp-react/templates/homepage/src/global.less +6 -5
- package/generators/subapp-react/templates/homepage/src/pages/index.less +3 -3
- package/generators/subapp-react/templates/homepage/src/pages/index.tsx +99 -60
- package/generators/subapp-react/templates/homepage/src/styles/theme.less +1 -1
- package/generators/subapp-umd/ignore-list.json +5 -0
- package/generators/subapp-umd/index.js +309 -0
- package/generators/subapp-umd/meta.json +11 -0
- package/generators/subapp-umd/templates/README.md +94 -0
- package/generators/subapp-umd/templates/package.json +35 -0
- package/generators/subapp-umd/templates/public/index.html +34 -0
- package/generators/subapp-umd/templates/src/App.less +15 -0
- package/generators/subapp-umd/templates/src/App.tsx +13 -0
- package/generators/subapp-umd/templates/src/index.ts +2 -0
- package/generators/subapp-umd/templates/tsconfig.json +27 -0
- package/generators/subapp-umd/templates/webpack.config.js +70 -0
- package/lib/utils.js +332 -2
- package/package.json +15 -2
- package/generators/micro-react/templates/apps/layout/mock/menus.json +0 -100
- package/generators/micro-react/templates/apps/layout/src/common/constants.ts +0 -38
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/container-manager.ts +0 -202
- package/generators/micro-react/templates/packages/shared-styles/README.md +0 -124
- package/generators/micro-react/templates/packages/shared-styles/arco-design-mobile-override.less +0 -91
- package/generators/micro-react/templates/packages/shared-styles/arco-override.less +0 -119
- package/generators/micro-react/templates/packages/shared-styles/index.d.ts +0 -44
- package/generators/micro-react/templates/packages/shared-styles/index.less +0 -13
- package/generators/micro-react/templates/packages/shared-styles/package.json +0 -30
- package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +0 -10
- package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +0 -290
- package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +0 -269
- package/generators/micro-react/templates/packages/shared-styles/variables-only.less +0 -433
- package/generators/micro-react/templates/packages/shared-styles/variables.less +0 -452
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"author": "Easton <easton@micous.com>",
|
|
5
5
|
"scripts": {
|
|
6
|
+
"check-types": "tsc --noEmit",
|
|
6
7
|
"build": "npm run build:production",
|
|
7
8
|
"build:development": "cross-env UMI_ENV=development max build",
|
|
8
9
|
"build:production": "cross-env UMI_ENV=production max build",
|
|
@@ -21,11 +22,9 @@
|
|
|
21
22
|
"test": "cross-env UMI_ENV=test max dev"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@
|
|
25
|
-
"
|
|
25
|
+
"@mico-platform/ui": "<%= micoUiVersion %>",
|
|
26
|
+
"@mico-platform/theme": "<%= themeVersion %>",
|
|
26
27
|
"@umijs/max": "^4.6.15",
|
|
27
|
-
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
28
|
-
"cross-env": "^10.1.0",
|
|
29
28
|
"dayjs": "^1.11.19",
|
|
30
29
|
"qiankun": "^2.10.16",
|
|
31
30
|
"react": "^18.2.0",
|
|
@@ -35,6 +34,10 @@
|
|
|
35
34
|
"devDependencies": {
|
|
36
35
|
"@types/react": "^18.0.33",
|
|
37
36
|
"@types/react-dom": "^18.0.11",
|
|
37
|
+
"@types/spark-md5": "^3.0.5",
|
|
38
|
+
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
39
|
+
"babel-plugin-import": "^1.13.8",
|
|
40
|
+
"cross-env": "^10.1.0",
|
|
38
41
|
"lint-staged": "^13.2.0",
|
|
39
42
|
"prettier": "^2.8.7",
|
|
40
43
|
"prettier-plugin-organize-imports": "^3.2.2",
|
|
@@ -1,93 +1,85 @@
|
|
|
1
1
|
import { history, type RequestConfig } from '@umijs/max';
|
|
2
|
-
import {
|
|
2
|
+
import { addGlobalUncaughtErrorHandler } from 'qiankun';
|
|
3
|
+
import { SentryErrorBoundary } from '@common-web/sentry';
|
|
3
4
|
import { errorConfig } from './requestErrorConfig';
|
|
4
|
-
//
|
|
5
|
-
import * as
|
|
6
|
-
import '@arco-design/web-react/dist/css/arco.css';
|
|
7
|
-
import '@arco-design/web-react/es/_util/react-19-adapter';
|
|
5
|
+
// 将 @mico-platform/ui 暴露到 window,供子应用 externals 使用
|
|
6
|
+
import * as micoUI from '@mico-platform/ui';
|
|
8
7
|
import React from 'react';
|
|
9
|
-
import ReactDOM from 'react-dom
|
|
8
|
+
import ReactDOM from 'react-dom';
|
|
10
9
|
|
|
11
10
|
import { getStoredAuthToken } from './common/auth/auth-manager';
|
|
12
11
|
import type { IUserInfo } from './common/auth/type';
|
|
13
12
|
import { fetchUserInfo } from './services/user';
|
|
14
|
-
import {
|
|
15
|
-
import { ensureSsoSession } from './common/request/sso';
|
|
13
|
+
import { getDynamicRoutes, isPageAuthFree } from './common/menu';
|
|
16
14
|
import {
|
|
17
15
|
clearMicroAppProps,
|
|
18
16
|
type IMicroAppProps,
|
|
19
17
|
setMicroAppProps,
|
|
20
18
|
} from './common/micro';
|
|
19
|
+
import {
|
|
20
|
+
clearRedirectCount,
|
|
21
|
+
ensureSsoSession,
|
|
22
|
+
handleAuthFailureRedirect,
|
|
23
|
+
} from './common/request/sso';
|
|
21
24
|
import { initTheme } from './common/theme';
|
|
22
25
|
import MicroAppLoader from './components/MicroAppLoader';
|
|
23
|
-
import {
|
|
26
|
+
import { isNoAuthRoute } from '@/constants';
|
|
27
|
+
import { getCurrentLocale } from '@/common/locale';
|
|
28
|
+
import '@mico-platform/theme/dist/css/theme.css';
|
|
24
29
|
import './global.less';
|
|
25
30
|
|
|
26
|
-
// ====================
|
|
27
|
-
//
|
|
28
|
-
// 当资源已预加载时,loadMicroApp 的异步加载会快速完成,减少容器不存在的错误
|
|
31
|
+
// ==================== qiankun 全局错误处理 ====================
|
|
32
|
+
// 捕获子应用运行时未捕获的异常,防止页面崩溃
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
+
* 注册 qiankun 全局未捕获错误处理器
|
|
36
|
+
* 处理以下场景:
|
|
37
|
+
* 1. 子应用 JS 运行时错误
|
|
38
|
+
* 2. 子应用生命周期钩子抛出的异常
|
|
39
|
+
* 3. 子应用资源加载失败
|
|
35
40
|
*/
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
41
|
+
if (typeof window !== 'undefined') {
|
|
42
|
+
addGlobalUncaughtErrorHandler((event: Event | string) => {
|
|
43
|
+
// 提取错误信息
|
|
44
|
+
const error =
|
|
45
|
+
event instanceof ErrorEvent
|
|
46
|
+
? event.error
|
|
47
|
+
: event instanceof PromiseRejectionEvent
|
|
48
|
+
? event.reason
|
|
49
|
+
: event;
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
const errorMessage =
|
|
52
|
+
error instanceof Error
|
|
53
|
+
? error.message
|
|
54
|
+
: typeof error === 'string'
|
|
55
|
+
? error
|
|
56
|
+
: 'Unknown micro-app error';
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
console.error('[qiankun] Global uncaught error:', {
|
|
59
|
+
error,
|
|
60
|
+
message: errorMessage,
|
|
61
|
+
type: event instanceof Event ? event.type : 'unknown',
|
|
62
|
+
});
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
// 检查是否是子应用加载失败(资源 404 等)
|
|
65
|
+
// 只匹配明确的关键词,避免误判业务错误(如 "upload failed")
|
|
66
|
+
const isLoadError =
|
|
67
|
+
errorMessage.includes('Failed to fetch') ||
|
|
68
|
+
errorMessage.includes('Loading chunk') ||
|
|
69
|
+
errorMessage.includes('ChunkLoadError') ||
|
|
70
|
+
errorMessage.includes('Script error') ||
|
|
71
|
+
errorMessage.includes('Loading CSS chunk') ||
|
|
72
|
+
(event instanceof ErrorEvent && event.type === 'error');
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// 筛选出所有微应用路由
|
|
66
|
-
const microApps = routes
|
|
67
|
-
.filter((route) => route.loadType === 'microapp' && route.entry)
|
|
68
|
-
.map((route) => ({
|
|
69
|
-
name: route.path,
|
|
70
|
-
entry: route.entry!,
|
|
71
|
-
}));
|
|
72
|
-
|
|
73
|
-
if (microApps.length > 0) {
|
|
74
|
-
console.log('[App] Prefetching micro apps:', microApps);
|
|
75
|
-
prefetchApps(microApps);
|
|
74
|
+
if (isLoadError) {
|
|
75
|
+
console.error(
|
|
76
|
+
'[qiankun] Micro-app resource loading failed. Please check if the micro-app server is running.',
|
|
77
|
+
);
|
|
76
78
|
}
|
|
77
|
-
} catch (error) {
|
|
78
|
-
console.warn('[App] Failed to prefetch micro apps:', error);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
79
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if ('requestIdleCallback' in window) {
|
|
86
|
-
window.requestIdleCallback(() => prefetchMicroApps(), { timeout: 3000 });
|
|
87
|
-
} else {
|
|
88
|
-
// 降级方案:延迟 1 秒后预加载
|
|
89
|
-
setTimeout(prefetchMicroApps, 1000);
|
|
90
|
-
}
|
|
80
|
+
// 注意:这里不阻止错误冒泡,让控制台仍能显示原始错误
|
|
81
|
+
// 如果需要阻止,可以 return true
|
|
82
|
+
});
|
|
91
83
|
}
|
|
92
84
|
|
|
93
85
|
// ==================== 微前端共享依赖 ====================
|
|
@@ -97,12 +89,24 @@ if (typeof window !== 'undefined') {
|
|
|
97
89
|
const win = window as unknown as Record<string, unknown>;
|
|
98
90
|
win.React = React;
|
|
99
91
|
win.ReactDOM = ReactDOM;
|
|
100
|
-
win.
|
|
92
|
+
win.micoUI = micoUI;
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
// 初始化主题(在页面加载时立即执行,避免闪烁)
|
|
104
96
|
initTheme();
|
|
105
97
|
|
|
98
|
+
// ==================== 国际化运行时配置 ====================
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 运行时国际化配置
|
|
102
|
+
* @see https://umijs.org/docs/max/i18n#%E8%BF%90%E8%A1%8C%E6%97%B6%E9%85%8D%E7%BD%AE
|
|
103
|
+
*/
|
|
104
|
+
export const locale = {
|
|
105
|
+
getLocale() {
|
|
106
|
+
return getCurrentLocale();
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
106
110
|
/**
|
|
107
111
|
* @see https://umijs.org/docs/api/runtime-config#getinitialstate
|
|
108
112
|
*/
|
|
@@ -124,29 +128,41 @@ export async function getInitialState(): Promise<{
|
|
|
124
128
|
}
|
|
125
129
|
};
|
|
126
130
|
|
|
127
|
-
// 如果不是登录页面,执行
|
|
128
131
|
const { location } = history;
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
const noAuthRoute = isNoAuthRoute(location.pathname);
|
|
133
|
+
const skipAuth = noAuthRoute || isPageAuthFree(location.pathname);
|
|
134
|
+
|
|
135
|
+
// 非免认证路由:走 SSO 流程
|
|
136
|
+
if (!skipAuth) {
|
|
131
137
|
await ensureSsoSession();
|
|
138
|
+
}
|
|
132
139
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
// 有 token 就获取用户信息(无论在哪个页面,支持登录后 refresh 场景)
|
|
141
|
+
// 当页面免认证时,不获取用户信息
|
|
142
|
+
if (getStoredAuthToken() && !skipAuth) {
|
|
143
|
+
const userInfo = await fetchUserInfoFn();
|
|
144
|
+
if (userInfo) {
|
|
145
|
+
clearRedirectCount();
|
|
146
|
+
return {
|
|
147
|
+
fetchUserInfo: fetchUserInfoFn,
|
|
148
|
+
currentUser: userInfo,
|
|
149
|
+
};
|
|
142
150
|
}
|
|
143
151
|
}
|
|
144
152
|
|
|
153
|
+
// 非免认证路由且没有 token,跳转到 SSO 登录
|
|
154
|
+
if (!skipAuth) {
|
|
155
|
+
handleAuthFailureRedirect();
|
|
156
|
+
// 返回空状态,页面会被重定向
|
|
157
|
+
return {
|
|
158
|
+
fetchUserInfo: fetchUserInfoFn,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
145
162
|
return {
|
|
146
163
|
fetchUserInfo: fetchUserInfoFn,
|
|
147
164
|
};
|
|
148
165
|
}
|
|
149
|
-
|
|
150
166
|
/**
|
|
151
167
|
* @name request 配置,可以配置错误处理
|
|
152
168
|
* 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。
|
|
@@ -158,6 +174,10 @@ export const request: RequestConfig = {
|
|
|
158
174
|
...errorConfig,
|
|
159
175
|
};
|
|
160
176
|
|
|
177
|
+
export function rootContainer(container: React.ReactNode) {
|
|
178
|
+
return <SentryErrorBoundary>{container}</SentryErrorBoundary>;
|
|
179
|
+
}
|
|
180
|
+
|
|
161
181
|
/**
|
|
162
182
|
* Umi 路由类型定义
|
|
163
183
|
*/
|
|
@@ -172,14 +192,16 @@ interface UmiRoute {
|
|
|
172
192
|
|
|
173
193
|
/**
|
|
174
194
|
* @name 动态路由配置
|
|
175
|
-
*
|
|
195
|
+
* 优先从 window.__MICO_PAGES__ 获取页面数据,无数据时降级到 window.__MICO_MENUS__
|
|
176
196
|
* @doc https://umijs.org/docs/max/router#%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1
|
|
177
197
|
*/
|
|
178
198
|
export function patchClientRoutes({ routes }: { routes: UmiRoute[] }) {
|
|
179
|
-
const
|
|
180
|
-
const dynamicRoutes = extractRoutes(menus);
|
|
199
|
+
const dynamicRoutes = getDynamicRoutes();
|
|
181
200
|
|
|
182
|
-
console.log('[app.tsx] patchClientRoutes:', {
|
|
201
|
+
console.log('[app.tsx] patchClientRoutes:', {
|
|
202
|
+
dynamicRoutes,
|
|
203
|
+
routes,
|
|
204
|
+
});
|
|
183
205
|
|
|
184
206
|
// 找到根路由(全局布局)
|
|
185
207
|
const rootRoute = routes.find((r) => r.path === '/');
|
|
@@ -205,6 +227,7 @@ export function patchClientRoutes({ routes }: { routes: UmiRoute[] }) {
|
|
|
205
227
|
? React.createElement(MicroAppLoader, {
|
|
206
228
|
entry: route.entry,
|
|
207
229
|
name: route.path,
|
|
230
|
+
base: route.base,
|
|
208
231
|
displayName: route.name,
|
|
209
232
|
})
|
|
210
233
|
: undefined;
|
|
@@ -222,6 +245,22 @@ export function patchClientRoutes({ routes }: { routes: UmiRoute[] }) {
|
|
|
222
245
|
});
|
|
223
246
|
}
|
|
224
247
|
|
|
248
|
+
/**
|
|
249
|
+
* @name 路由变化处理
|
|
250
|
+
* @description 处理 defaultPath 重定向:访问 "/" 时自动跳转到配置的默认路径
|
|
251
|
+
* @doc https://umijs.org/docs/api/runtime-config#onroutechange
|
|
252
|
+
*/
|
|
253
|
+
export function onRouteChange({
|
|
254
|
+
location,
|
|
255
|
+
}: {
|
|
256
|
+
location: { pathname: string };
|
|
257
|
+
}) {
|
|
258
|
+
const defaultPath = window.__MICO_CONFIG__?.defaultPath;
|
|
259
|
+
if (location.pathname === '/' && defaultPath && defaultPath !== '/') {
|
|
260
|
+
history.replace(defaultPath);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
225
264
|
/**
|
|
226
265
|
* @name qiankun 微前端子应用生命周期
|
|
227
266
|
* @description 当应用作为 qiankun 子应用运行时,这些生命周期会被调用
|
|
@@ -3,6 +3,9 @@ import { checkStaffAuth } from '@/services/auth';
|
|
|
3
3
|
import { handleAuthFailureRedirect } from '../request';
|
|
4
4
|
import { clearStoredTokens, getAuthInfo } from './auth-manager';
|
|
5
5
|
|
|
6
|
+
// 导出 STORAGE_KEYS 常量
|
|
7
|
+
export { STORAGE_KEYS } from '../../constants';
|
|
8
|
+
|
|
6
9
|
export function logout(): void {
|
|
7
10
|
clearStoredTokens();
|
|
8
11
|
}
|
|
@@ -1,11 +1,188 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
import timezone from 'dayjs/plugin/timezone';
|
|
3
3
|
import utc from 'dayjs/plugin/utc';
|
|
4
|
+
import { STORAGE_KEYS } from '../constants';
|
|
4
5
|
|
|
5
6
|
// 扩展 dayjs
|
|
6
7
|
dayjs.extend(utc);
|
|
7
8
|
dayjs.extend(timezone);
|
|
8
9
|
|
|
10
|
+
// ==================== 时区常量 ====================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* UTC 偏移量键的枚举映射,覆盖 UTC-12 到 UTC+14
|
|
14
|
+
*/
|
|
15
|
+
export const TIMEZONE = {
|
|
16
|
+
'UTC-12': 'UTC-12',
|
|
17
|
+
'UTC-11': 'UTC-11',
|
|
18
|
+
'UTC-10': 'UTC-10',
|
|
19
|
+
'UTC-9': 'UTC-9',
|
|
20
|
+
'UTC-8': 'UTC-8',
|
|
21
|
+
'UTC-7': 'UTC-7',
|
|
22
|
+
'UTC-6': 'UTC-6',
|
|
23
|
+
'UTC-5': 'UTC-5',
|
|
24
|
+
'UTC-4': 'UTC-4',
|
|
25
|
+
'UTC-3': 'UTC-3',
|
|
26
|
+
'UTC-2': 'UTC-2',
|
|
27
|
+
'UTC-1': 'UTC-1',
|
|
28
|
+
'UTC+0': 'UTC+0',
|
|
29
|
+
'UTC+1': 'UTC+1',
|
|
30
|
+
'UTC+2': 'UTC+2',
|
|
31
|
+
'UTC+3': 'UTC+3',
|
|
32
|
+
'UTC+4': 'UTC+4',
|
|
33
|
+
'UTC+5': 'UTC+5',
|
|
34
|
+
'UTC+6': 'UTC+6',
|
|
35
|
+
'UTC+7': 'UTC+7',
|
|
36
|
+
'UTC+8': 'UTC+8',
|
|
37
|
+
'UTC+9': 'UTC+9',
|
|
38
|
+
'UTC+10': 'UTC+10',
|
|
39
|
+
'UTC+11': 'UTC+11',
|
|
40
|
+
'UTC+12': 'UTC+12',
|
|
41
|
+
'UTC+13': 'UTC+13',
|
|
42
|
+
'UTC+14': 'UTC+14',
|
|
43
|
+
} as const;
|
|
44
|
+
|
|
45
|
+
export type TTimezone = keyof typeof TIMEZONE;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* UTC 偏移量到 IANA 时区标识的映射表
|
|
49
|
+
* 每个整数偏移值对应一个具有常住人口的代表性城市/地区
|
|
50
|
+
*/
|
|
51
|
+
export const TIMEZONE_HASH: Record<TTimezone, string> = {
|
|
52
|
+
[TIMEZONE['UTC-12']]: 'Etc/GMT+12', // 无居住区(公海/无人岛)
|
|
53
|
+
[TIMEZONE['UTC-11']]: 'Pacific/Pago_Pago', // 帕果帕果,美属萨摩亚
|
|
54
|
+
[TIMEZONE['UTC-10']]: 'Pacific/Honolulu', // 檀香山,夏威夷州
|
|
55
|
+
[TIMEZONE['UTC-9']]: 'America/Anchorage', // 安克雷奇,阿拉斯加州
|
|
56
|
+
[TIMEZONE['UTC-8']]: 'America/Los_Angeles', // 洛杉矶,加利福尼亚州
|
|
57
|
+
[TIMEZONE['UTC-7']]: 'America/Denver', // 丹佛,科罗拉多州
|
|
58
|
+
[TIMEZONE['UTC-6']]: 'America/Chicago', // 芝加哥,伊利诺伊州
|
|
59
|
+
[TIMEZONE['UTC-5']]: 'America/New_York', // 纽约,纽约州
|
|
60
|
+
[TIMEZONE['UTC-4']]: 'America/Puerto_Rico', // 圣胡安,波多黎各
|
|
61
|
+
[TIMEZONE['UTC-3']]: 'America/Sao_Paulo', // 圣保罗,巴西
|
|
62
|
+
[TIMEZONE['UTC-2']]: 'America/Noronha', // 费尔南多岛,巴西
|
|
63
|
+
[TIMEZONE['UTC-1']]: 'Atlantic/Azores', // 亚速尔群岛,葡萄牙
|
|
64
|
+
[TIMEZONE['UTC+0']]: 'Europe/London', // 伦敦,英国
|
|
65
|
+
[TIMEZONE['UTC+1']]: 'Europe/Paris', // 巴黎,法国
|
|
66
|
+
[TIMEZONE['UTC+2']]: 'Europe/Kyiv', // 基辅,乌克兰
|
|
67
|
+
[TIMEZONE['UTC+3']]: 'Europe/Moscow', // 莫斯科,俄罗斯
|
|
68
|
+
[TIMEZONE['UTC+4']]: 'Asia/Dubai', // 迪拜,阿联酋
|
|
69
|
+
[TIMEZONE['UTC+5']]: 'Asia/Tashkent', // 塔什干,乌兹别克斯坦
|
|
70
|
+
[TIMEZONE['UTC+6']]: 'Asia/Dhaka', // 达卡,孟加拉国
|
|
71
|
+
[TIMEZONE['UTC+7']]: 'Asia/Bangkok', // 曼谷,泰国
|
|
72
|
+
[TIMEZONE['UTC+8']]: 'Asia/Shanghai', // 上海,中国(默认)
|
|
73
|
+
[TIMEZONE['UTC+9']]: 'Asia/Tokyo', // 东京,日本
|
|
74
|
+
[TIMEZONE['UTC+10']]: 'Australia/Sydney', // 悉尼,澳大利亚
|
|
75
|
+
[TIMEZONE['UTC+11']]: 'Pacific/Noumea', // 努美阿,新喀里多尼亚
|
|
76
|
+
[TIMEZONE['UTC+12']]: 'Pacific/Auckland', // 奥克兰,新西兰
|
|
77
|
+
[TIMEZONE['UTC+13']]: 'Pacific/Tongatapu', // 努库阿洛法,汤加
|
|
78
|
+
[TIMEZONE['UTC+14']]: 'Pacific/Kiritimati', // 圣诞岛,基里巴斯
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// ==================== 时区工具函数 ====================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 将 UTC offset 数字转换为 UTC+N 格式的时区字符串
|
|
85
|
+
* @param utcOffset UTC 偏移量(数字),如 8 表示 UTC+8,-5 表示 UTC-5
|
|
86
|
+
* @returns 时区字符串,如 'UTC+8' 或 'UTC-5'
|
|
87
|
+
*/
|
|
88
|
+
export const utcOffsetToTimezone = (utcOffset: number): string => {
|
|
89
|
+
if (utcOffset >= 0) {
|
|
90
|
+
return `UTC+${utcOffset}`;
|
|
91
|
+
}
|
|
92
|
+
return `UTC${utcOffset}`; // 负数会自动包含负号
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 将 UTC 偏移量转换为 IANA 时区标识
|
|
97
|
+
* @param utcOffset UTC 偏移量
|
|
98
|
+
* @returns IANA 时区标识(如 'Asia/Shanghai')
|
|
99
|
+
*/
|
|
100
|
+
export const utcOffsetToTimeZoneStr = (utcOffset: number): string => {
|
|
101
|
+
const timezoneKey = utcOffsetToTimezone(utcOffset) as TTimezone;
|
|
102
|
+
return (
|
|
103
|
+
TIMEZONE_HASH[timezoneKey] ??
|
|
104
|
+
dayjs.tz.guess() ??
|
|
105
|
+
TIMEZONE_HASH[TIMEZONE['UTC+8']]
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 从 localStorage 获取时区偏移量数字
|
|
111
|
+
* @returns 偏移量数字,默认 8(UTC+8)
|
|
112
|
+
*/
|
|
113
|
+
export const getTimezoneOffset = (): number => {
|
|
114
|
+
return Number(getFromStorage(STORAGE_KEYS.TIMEZONE)) || 8;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 获取当前时区的 IANA 标识
|
|
119
|
+
* @returns IANA 时区标识(如 'Asia/Shanghai')
|
|
120
|
+
*/
|
|
121
|
+
export const getTimezone = (): string => {
|
|
122
|
+
const storedTimezone = getFromStorage(STORAGE_KEYS.TIMEZONE);
|
|
123
|
+
let timezoneKey: TTimezone | undefined;
|
|
124
|
+
|
|
125
|
+
if (storedTimezone) {
|
|
126
|
+
// 如果存储的是数字字符串(UTC offset),转换为 UTC+N 格式
|
|
127
|
+
const offsetNum = Number(storedTimezone);
|
|
128
|
+
if (!Number.isNaN(offsetNum) && storedTimezone.trim() !== '') {
|
|
129
|
+
timezoneKey = utcOffsetToTimezone(offsetNum) as TTimezone;
|
|
130
|
+
} else {
|
|
131
|
+
// 如果已经是 UTC+N 格式,直接使用
|
|
132
|
+
timezoneKey = storedTimezone as TTimezone;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
(timezoneKey && TIMEZONE_HASH[timezoneKey]) ??
|
|
138
|
+
dayjs.tz.guess() ??
|
|
139
|
+
TIMEZONE_HASH[TIMEZONE['UTC+8']]
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 获取当前时区(从 localStorage 读取)
|
|
145
|
+
* @returns 时区字符串,如 'UTC+8',如果未设置则返回 'UTC+8'
|
|
146
|
+
*/
|
|
147
|
+
export const getCurrentTimezone = (): string => {
|
|
148
|
+
const stored = getFromStorage(STORAGE_KEYS.TIMEZONE);
|
|
149
|
+
if (stored) {
|
|
150
|
+
// 如果存储的是数字字符串(UTC offset),转换为 UTC+N 格式
|
|
151
|
+
const offsetNum = Number(stored);
|
|
152
|
+
if (!Number.isNaN(offsetNum) && stored.trim() !== '') {
|
|
153
|
+
return utcOffsetToTimezone(offsetNum);
|
|
154
|
+
}
|
|
155
|
+
// 如果已经是 UTC+N 格式,直接返回
|
|
156
|
+
return stored;
|
|
157
|
+
}
|
|
158
|
+
// 默认返回 UTC+8
|
|
159
|
+
return TIMEZONE['UTC+8'];
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 设置时区到 localStorage
|
|
164
|
+
* @param timezone 时区字符串,如 'UTC+8' 或偏移量数字字符串如 '8'
|
|
165
|
+
*/
|
|
166
|
+
export const setTimezone = (timezone: string): void => {
|
|
167
|
+
setStorage(STORAGE_KEYS.TIMEZONE, timezone);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 获取时区地区(IANA 标识)
|
|
172
|
+
* @returns 时区地区字符串,如 'Asia/Shanghai',如果未设置则返回空字符串
|
|
173
|
+
*/
|
|
174
|
+
export const getTimezoneRegion = (): string => {
|
|
175
|
+
return getFromStorage(STORAGE_KEYS.TIMEZONE_REGION) || '';
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 设置时区地区到 localStorage
|
|
180
|
+
* @param region 时区地区字符串,如 'Asia/Shanghai'
|
|
181
|
+
*/
|
|
182
|
+
export const setTimezoneRegion = (region: string): void => {
|
|
183
|
+
setStorage(STORAGE_KEYS.TIMEZONE_REGION, region);
|
|
184
|
+
};
|
|
185
|
+
|
|
9
186
|
/**
|
|
10
187
|
* 获取静态资源的完整 URL
|
|
11
188
|
* 用于 public 目录下的静态资源,自动拼接 publicPath 前缀
|
|
@@ -12,11 +12,19 @@ const LOCALE_STORAGE_KEY = 'umi_locale';
|
|
|
12
12
|
const URL_PARAM_KEY = 'lang';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* 支持的语言列表(umi 格式)
|
|
16
16
|
*/
|
|
17
|
-
export const SUPPORTED_LOCALES = ['zh-CN', 'en-US'
|
|
17
|
+
export const SUPPORTED_LOCALES = ['zh-CN', 'en-US'] as const;
|
|
18
18
|
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* 语言枚举常量
|
|
22
|
+
*/
|
|
23
|
+
export const LOCALE = {
|
|
24
|
+
ZH_CN: 'zh-CN',
|
|
25
|
+
EN_US: 'en-US',
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
20
28
|
/**
|
|
21
29
|
* 默认语言
|
|
22
30
|
*/
|
|
@@ -50,20 +58,19 @@ function getLocaleFromStorage(): string | null {
|
|
|
50
58
|
/**
|
|
51
59
|
* 获取浏览器默认语言
|
|
52
60
|
*/
|
|
53
|
-
function getBrowserLocale():
|
|
61
|
+
function getBrowserLocale(): SupportedLocale {
|
|
54
62
|
if (typeof window === 'undefined') {
|
|
55
63
|
return DEFAULT_LOCALE;
|
|
56
64
|
}
|
|
57
65
|
const browserLang = navigator.language || (navigator as any).userLanguage;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
const locales = [...SUPPORTED_LOCALES];
|
|
67
|
+
// 检查是否直接支持该语言
|
|
68
|
+
if (locales.includes(browserLang as SupportedLocale)) {
|
|
69
|
+
return browserLang as SupportedLocale;
|
|
61
70
|
}
|
|
62
|
-
// 检查语言前缀(如 zh-TW -> zh-CN)
|
|
71
|
+
// 检查语言前缀(如 zh-TW -> zh-CN, en-GB -> en-US)
|
|
63
72
|
const langPrefix = browserLang.split('-')[0];
|
|
64
|
-
const matchedLocale =
|
|
65
|
-
locale.startsWith(langPrefix),
|
|
66
|
-
);
|
|
73
|
+
const matchedLocale = locales.find((locale) => locale.startsWith(langPrefix));
|
|
67
74
|
return matchedLocale || DEFAULT_LOCALE;
|
|
68
75
|
}
|
|
69
76
|
|
|
@@ -74,7 +81,7 @@ function isValidLocale(locale: string | null): locale is SupportedLocale {
|
|
|
74
81
|
if (!locale) {
|
|
75
82
|
return false;
|
|
76
83
|
}
|
|
77
|
-
return SUPPORTED_LOCALES.includes(locale
|
|
84
|
+
return ([...SUPPORTED_LOCALES] as string[]).includes(locale);
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
/**
|
|
@@ -95,7 +102,7 @@ export function getCurrentLocale(): SupportedLocale {
|
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
// 3. 使用浏览器默认语言
|
|
98
|
-
return getBrowserLocale()
|
|
105
|
+
return getBrowserLocale();
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
/**
|
|
@@ -115,9 +122,7 @@ export function setLocaleToStorage(locale: SupportedLocale): void {
|
|
|
115
122
|
/**
|
|
116
123
|
* 根据语言获取图标库路径
|
|
117
124
|
*/
|
|
118
|
-
export function getIconFontPath(locale: SupportedLocale): string {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
return withPublicPath('/font/default.js');
|
|
125
|
+
export function getIconFontPath(/* locale: SupportedLocale */): string {
|
|
126
|
+
// 如果后续需要支持 RTL 语言(如阿拉伯语),可在此扩展
|
|
127
|
+
return withPublicPath("/font/default.js");
|
|
123
128
|
}
|