generator-mico-cli 0.1.18

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 (155) hide show
  1. package/README.md +84 -0
  2. package/bin/mico.js +316 -0
  3. package/generators/micro-react/ignore-list.json +8 -0
  4. package/generators/micro-react/index.js +158 -0
  5. package/generators/micro-react/templates/.commitlintrc.js +6 -0
  6. package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +129 -0
  7. package/generators/micro-react/templates/.cursor/rules/cicd-deploy.mdc +143 -0
  8. package/generators/micro-react/templates/.cursor/rules/coding-conventions.mdc +206 -0
  9. package/generators/micro-react/templates/.cursor/rules/commit-conventions.mdc +111 -0
  10. package/generators/micro-react/templates/.cursor/rules/development-guide.mdc +295 -0
  11. package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +275 -0
  12. package/generators/micro-react/templates/.cursor/rules/micro-frontend.mdc +196 -0
  13. package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +128 -0
  14. package/generators/micro-react/templates/.cursor/rules/request-auth.mdc +220 -0
  15. package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +206 -0
  16. package/generators/micro-react/templates/.editorconfig +16 -0
  17. package/generators/micro-react/templates/.env +3 -0
  18. package/generators/micro-react/templates/.eslintrc.js +30 -0
  19. package/generators/micro-react/templates/.husky/commit-msg +2 -0
  20. package/generators/micro-react/templates/.husky/pre-commit +2 -0
  21. package/generators/micro-react/templates/.lintstagedrc +5 -0
  22. package/generators/micro-react/templates/.stylelintrc.js +25 -0
  23. package/generators/micro-react/templates/AGENTS.md +39 -0
  24. package/generators/micro-react/templates/CICD/start_dev.sh +30 -0
  25. package/generators/micro-react/templates/CICD/start_local.sh +30 -0
  26. package/generators/micro-react/templates/CICD/start_prod.sh +30 -0
  27. package/generators/micro-react/templates/CICD/start_test.sh +30 -0
  28. package/generators/micro-react/templates/CICD/wangsu_fresh_dev.sh +19 -0
  29. package/generators/micro-react/templates/CICD/wangsu_fresh_prod.sh +19 -0
  30. package/generators/micro-react/templates/CICD/wangsu_fresh_test.sh +19 -0
  31. package/generators/micro-react/templates/CLAUDE.md +106 -0
  32. package/generators/micro-react/templates/README.md +84 -0
  33. package/generators/micro-react/templates/_gitignore +57 -0
  34. package/generators/micro-react/templates/_npmrc +2 -0
  35. package/generators/micro-react/templates/apps/layout/.env +4 -0
  36. package/generators/micro-react/templates/apps/layout/.eslintrc.js +10 -0
  37. package/generators/micro-react/templates/apps/layout/.lintstagedrc +17 -0
  38. package/generators/micro-react/templates/apps/layout/.prettierignore +3 -0
  39. package/generators/micro-react/templates/apps/layout/.prettierrc +8 -0
  40. package/generators/micro-react/templates/apps/layout/.stylelintrc.js +20 -0
  41. package/generators/micro-react/templates/apps/layout/README.md +37 -0
  42. package/generators/micro-react/templates/apps/layout/config/config.dev.ts +54 -0
  43. package/generators/micro-react/templates/apps/layout/config/config.prod.ts +37 -0
  44. package/generators/micro-react/templates/apps/layout/config/config.testing.ts +27 -0
  45. package/generators/micro-react/templates/apps/layout/config/config.ts +132 -0
  46. package/generators/micro-react/templates/apps/layout/config/routes.ts +13 -0
  47. package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +78 -0
  48. package/generators/micro-react/templates/apps/layout/mock/menus.json +100 -0
  49. package/generators/micro-react/templates/apps/layout/mock/menus.ts +11 -0
  50. package/generators/micro-react/templates/apps/layout/mock/user.mock.ts +20 -0
  51. package/generators/micro-react/templates/apps/layout/package.json +45 -0
  52. package/generators/micro-react/templates/apps/layout/public/font/ar-SA.js +54 -0
  53. package/generators/micro-react/templates/apps/layout/public/font/default.js +54 -0
  54. package/generators/micro-react/templates/apps/layout/src/app.tsx +123 -0
  55. package/generators/micro-react/templates/apps/layout/src/assets/.gitkeep +0 -0
  56. package/generators/micro-react/templates/apps/layout/src/common/auth/cs-auth-manager.ts +220 -0
  57. package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +41 -0
  58. package/generators/micro-react/templates/apps/layout/src/common/auth/tool.ts +3 -0
  59. package/generators/micro-react/templates/apps/layout/src/common/auth/type.ts +6 -0
  60. package/generators/micro-react/templates/apps/layout/src/common/constants.ts +38 -0
  61. package/generators/micro-react/templates/apps/layout/src/common/env.ts +73 -0
  62. package/generators/micro-react/templates/apps/layout/src/common/helpers.ts +69 -0
  63. package/generators/micro-react/templates/apps/layout/src/common/locale.ts +123 -0
  64. package/generators/micro-react/templates/apps/layout/src/common/logger.ts +45 -0
  65. package/generators/micro-react/templates/apps/layout/src/common/menu/index.ts +2 -0
  66. package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +143 -0
  67. package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +92 -0
  68. package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +73 -0
  69. package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +188 -0
  70. package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +186 -0
  71. package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +132 -0
  72. package/generators/micro-react/templates/apps/layout/src/common/request/token-refresh.ts +136 -0
  73. package/generators/micro-react/templates/apps/layout/src/common/request/types.ts +44 -0
  74. package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +75 -0
  75. package/generators/micro-react/templates/apps/layout/src/common/theme.ts +107 -0
  76. package/generators/micro-react/templates/apps/layout/src/common/types.ts +7 -0
  77. package/generators/micro-react/templates/apps/layout/src/common/upload/index.ts +2 -0
  78. package/generators/micro-react/templates/apps/layout/src/common/upload/oss.ts +401 -0
  79. package/generators/micro-react/templates/apps/layout/src/common/upload/types.ts +47 -0
  80. package/generators/micro-react/templates/apps/layout/src/common/uploadFiles.ts +35 -0
  81. package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +25 -0
  82. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +44 -0
  83. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +121 -0
  84. package/generators/micro-react/templates/apps/layout/src/constants/index.ts +15 -0
  85. package/generators/micro-react/templates/apps/layout/src/global.less +13 -0
  86. package/generators/micro-react/templates/apps/layout/src/hooks/index.ts +3 -0
  87. package/generators/micro-react/templates/apps/layout/src/hooks/useAuth.ts +75 -0
  88. package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +35 -0
  89. package/generators/micro-react/templates/apps/layout/src/hooks/useMenuState.ts +112 -0
  90. package/generators/micro-react/templates/apps/layout/src/hooks/useTheme.ts +124 -0
  91. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +109 -0
  92. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +97 -0
  93. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +164 -0
  94. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +165 -0
  95. package/generators/micro-react/templates/apps/layout/src/layouts/index.less +71 -0
  96. package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +91 -0
  97. package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +20 -0
  98. package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +19 -0
  99. package/generators/micro-react/templates/apps/layout/src/models/global.ts +13 -0
  100. package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +3 -0
  101. package/generators/micro-react/templates/apps/layout/src/pages/Home/index.tsx +7 -0
  102. package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +171 -0
  103. package/generators/micro-react/templates/apps/layout/src/services/auth.ts +37 -0
  104. package/generators/micro-react/templates/apps/layout/src/services/oss.ts +40 -0
  105. package/generators/micro-react/templates/apps/layout/src/styles/arco-override.less +78 -0
  106. package/generators/micro-react/templates/apps/layout/src/styles/themes/dark/custom-var.less +244 -0
  107. package/generators/micro-react/templates/apps/layout/src/styles/themes/normal/custom-var.less +195 -0
  108. package/generators/micro-react/templates/apps/layout/src/styles/variables.less +5 -0
  109. package/generators/micro-react/templates/apps/layout/src/utils/format.ts +4 -0
  110. package/generators/micro-react/templates/apps/layout/tailwind.config.js +7 -0
  111. package/generators/micro-react/templates/apps/layout/tailwind.css +3 -0
  112. package/generators/micro-react/templates/apps/layout/tsconfig.json +3 -0
  113. package/generators/micro-react/templates/apps/layout/typings.d.ts +1 -0
  114. package/generators/micro-react/templates/deployDesc.md +60 -0
  115. package/generators/micro-react/templates/docs/commit-message.md +98 -0
  116. package/generators/micro-react/templates/package.json +35 -0
  117. package/generators/micro-react/templates/packages/shared-styles/README.md +125 -0
  118. package/generators/micro-react/templates/packages/shared-styles/arco-override.less +78 -0
  119. package/generators/micro-react/templates/packages/shared-styles/index.less +14 -0
  120. package/generators/micro-react/templates/packages/shared-styles/package.json +27 -0
  121. package/generators/micro-react/templates/packages/shared-styles/theme-inject.less +10 -0
  122. package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +246 -0
  123. package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +195 -0
  124. package/generators/micro-react/templates/packages/shared-styles/variables-only.less +301 -0
  125. package/generators/micro-react/templates/packages/shared-styles/variables.less +363 -0
  126. package/generators/micro-react/templates/pnpm-workspace.yaml +9 -0
  127. package/generators/micro-react/templates/scripts/collect-dist.js +68 -0
  128. package/generators/micro-react/templates/scripts/create-umi-app.sh +61 -0
  129. package/generators/micro-react/templates/scripts/dev.js +133 -0
  130. package/generators/micro-react/templates/turbo.json +68 -0
  131. package/generators/subapp-react/ignore-list.json +7 -0
  132. package/generators/subapp-react/index.js +189 -0
  133. package/generators/subapp-react/templates/homepage/.env +4 -0
  134. package/generators/subapp-react/templates/homepage/README.md +116 -0
  135. package/generators/subapp-react/templates/homepage/_gitignore +9 -0
  136. package/generators/subapp-react/templates/homepage/config/config.dev.ts +59 -0
  137. package/generators/subapp-react/templates/homepage/config/config.prod.ts +41 -0
  138. package/generators/subapp-react/templates/homepage/config/config.testing.ts +40 -0
  139. package/generators/subapp-react/templates/homepage/config/config.ts +102 -0
  140. package/generators/subapp-react/templates/homepage/config/routes.ts +7 -0
  141. package/generators/subapp-react/templates/homepage/mock/api.mock.ts +59 -0
  142. package/generators/subapp-react/templates/homepage/package.json +30 -0
  143. package/generators/subapp-react/templates/homepage/src/app.tsx +80 -0
  144. package/generators/subapp-react/templates/homepage/src/assets/yay.jpg +0 -0
  145. package/generators/subapp-react/templates/homepage/src/common/logger.ts +42 -0
  146. package/generators/subapp-react/templates/homepage/src/common/mainApp.ts +53 -0
  147. package/generators/subapp-react/templates/homepage/src/common/request.ts +49 -0
  148. package/generators/subapp-react/templates/homepage/src/global.less +26 -0
  149. package/generators/subapp-react/templates/homepage/src/pages/index.less +139 -0
  150. package/generators/subapp-react/templates/homepage/src/pages/index.tsx +342 -0
  151. package/generators/subapp-react/templates/homepage/src/styles/theme.less +6 -0
  152. package/generators/subapp-react/templates/homepage/tsconfig.json +3 -0
  153. package/generators/subapp-react/templates/homepage/typings.d.ts +17 -0
  154. package/lib/utils.js +165 -0
  155. package/package.json +31 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 日志工具
3
+ * 仅在开发环境下输出日志,生产环境自动静默
4
+ *
5
+ * 使用 bind 保持原始调用位置,避免错误栈指向 logger 内部
6
+ */
7
+
8
+ const isDev = process.env.NODE_ENV === 'development';
9
+
10
+ // 空操作函数(生产环境使用)
11
+ const noop = (): void => {};
12
+
13
+ /**
14
+ * 创建带前缀的日志函数
15
+ * 使用 bind 绑定前缀,保持控制台显示正确的调用位置
16
+ */
17
+ const createLogger = (prefix: string) => {
18
+ if (!isDev) {
19
+ // 生产环境返回空操作
20
+ return {
21
+ log: noop,
22
+ info: noop,
23
+ warn: noop,
24
+ error: noop,
25
+ };
26
+ }
27
+
28
+ const formattedPrefix = `[${prefix}]`;
29
+
30
+ return {
31
+ log: console.log.bind(console, formattedPrefix),
32
+ info: console.info.bind(console, formattedPrefix),
33
+ warn: console.warn.bind(console, formattedPrefix),
34
+ error: console.error.bind(console, formattedPrefix),
35
+ };
36
+ };
37
+
38
+ // 预定义的日志实例
39
+ export const layoutLogger = createLogger('Layout');
40
+ export const microAppLogger = createLogger('MicroAppLoader');
41
+ export const authLogger = createLogger('Auth');
42
+ export const requestLogger = createLogger('Request');
43
+
44
+ // 导出创建器供自定义使用
45
+ export { createLogger };
@@ -0,0 +1,2 @@
1
+ export * from './parser';
2
+ export * from './types';
@@ -0,0 +1,143 @@
1
+ import type { MenuItem, ParsedMenuItem, ParsedRoute } from './types';
2
+
3
+ /**
4
+ * 获取 window 上挂载的菜单数据
5
+ */
6
+ export const getWindowMenus = (): MenuItem[] => {
7
+ return window.__MICO_MENUS__ || [];
8
+ };
9
+
10
+ /**
11
+ * 判断页面的加载类型
12
+ * 有 htmlUrl 或 jsUrls 时使用 qiankun 微应用加载
13
+ */
14
+ const getLoadType = (page: MenuItem['page']): 'internal' | 'microapp' => {
15
+ if (!page) return 'internal';
16
+
17
+ // 有 htmlUrl 或 jsUrls 使用 qiankun 微应用加载
18
+ if (page.htmlUrl || (page.jsUrls && page.jsUrls.length > 0)) {
19
+ return 'microapp';
20
+ }
21
+
22
+ // 否则使用内部路由
23
+ return 'internal';
24
+ };
25
+
26
+ /**
27
+ * 获取微应用入口 URL
28
+ * 优先使用 htmlUrl,其次使用 jsUrls[0]
29
+ */
30
+ const getEntry = (page: MenuItem['page']): string | undefined => {
31
+ if (!page) return undefined;
32
+ return page.htmlUrl || page.jsUrls?.[0] || undefined;
33
+ };
34
+
35
+ /**
36
+ * 递归提取所有路由配置
37
+ */
38
+ export const extractRoutes = (
39
+ items: MenuItem[],
40
+ routes: ParsedRoute[] = [],
41
+ ): ParsedRoute[] => {
42
+ for (const item of items) {
43
+ if (!item.enabled) continue;
44
+
45
+ if (item.type === 'page' && item.page && item.page.enabled) {
46
+ const loadType = getLoadType(item.page);
47
+ routes.push({
48
+ path: item.page.route,
49
+ name: item.name,
50
+ icon: item.icon,
51
+ loadType,
52
+ entry: getEntry(item.page),
53
+ pageConfig: item.page,
54
+ });
55
+ }
56
+
57
+ if (item.children && item.children.length > 0) {
58
+ extractRoutes(item.children, routes);
59
+ }
60
+ }
61
+
62
+ return routes;
63
+ };
64
+
65
+ /**
66
+ * 将菜单数据转换为菜单组件需要的格式
67
+ */
68
+ export const parseMenuItems = (items: MenuItem[]): ParsedMenuItem[] => {
69
+ return items
70
+ .filter((item) => item.enabled)
71
+ .sort((a, b) => a.sortOrder - b.sortOrder)
72
+ .map((item) => {
73
+ const parsed: ParsedMenuItem = {
74
+ key: String(item.id),
75
+ label: item.name,
76
+ icon: item.icon,
77
+ type: item.type,
78
+ };
79
+
80
+ if (item.type === 'link' && item.path) {
81
+ parsed.path = item.path;
82
+ } else if (item.type === 'page' && item.page) {
83
+ parsed.path = item.page.route;
84
+ }
85
+
86
+ if (item.children && item.children.length > 0) {
87
+ parsed.children = parseMenuItems(item.children);
88
+ }
89
+
90
+ return parsed;
91
+ });
92
+ };
93
+
94
+ /**
95
+ * 根据路径查找对应的路由配置
96
+ */
97
+ export const findRouteByPath = (
98
+ routes: ParsedRoute[],
99
+ pathname: string,
100
+ ): ParsedRoute | undefined => {
101
+ return routes.find((route) => {
102
+ // 处理通配符路由 /test/*
103
+ if (route.path.endsWith('/*')) {
104
+ const basePath = route.path.slice(0, -2);
105
+ return pathname.startsWith(basePath);
106
+ }
107
+ // 精确匹配
108
+ return route.path === pathname;
109
+ });
110
+ };
111
+
112
+ /**
113
+ * 根据路径查找对应的菜单项 key
114
+ */
115
+ export const findMenuKeyByPath = (
116
+ items: ParsedMenuItem[],
117
+ pathname: string,
118
+ parentKeys: string[] = [],
119
+ ): { key: string; openKeys: string[] } | null => {
120
+ for (const item of items) {
121
+ if (item.path) {
122
+ // 处理通配符路由
123
+ if (item.path.endsWith('/*')) {
124
+ const basePath = item.path.slice(0, -2);
125
+ if (pathname.startsWith(basePath)) {
126
+ return { key: item.key, openKeys: parentKeys };
127
+ }
128
+ } else if (item.path === pathname) {
129
+ return { key: item.key, openKeys: parentKeys };
130
+ }
131
+ }
132
+
133
+ if (item.children && item.children.length > 0) {
134
+ const result = findMenuKeyByPath(item.children, pathname, [
135
+ ...parentKeys,
136
+ item.key,
137
+ ]);
138
+ if (result) return result;
139
+ }
140
+ }
141
+
142
+ return null;
143
+ };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * 页面配置 - 从统一中台获取
3
+ */
4
+ export interface PageConfig {
5
+ id: number;
6
+ name: string;
7
+ /** 路由路径 */
8
+ route: string;
9
+ enabled: boolean;
10
+ /** 微应用 HTML 入口 URL (用于 qiankun 加载) */
11
+ htmlUrl: string | null;
12
+ /** 微应用 JS 入口 URL 列表 */
13
+ jsUrls: string[];
14
+ /** 微应用 CSS URL 列表 */
15
+ cssUrls: string[];
16
+ }
17
+
18
+ /**
19
+ * 菜单项类型
20
+ */
21
+ export type MenuItemType = 'group' | 'page' | 'link';
22
+
23
+ /**
24
+ * 菜单项配置 - 从统一中台获取
25
+ */
26
+ export interface MenuItem {
27
+ id: number;
28
+ name: string;
29
+ type: MenuItemType;
30
+ /** 路由路径或外链地址 */
31
+ path: string | null;
32
+ /** 图标名称 */
33
+ icon: string;
34
+ enabled: boolean;
35
+ sortOrder: number;
36
+ pageId: number | null;
37
+ /** 页面配置(type=page 时存在) */
38
+ page: PageConfig | null;
39
+ children: MenuItem[];
40
+ }
41
+
42
+ /**
43
+ * 解析后的路由配置
44
+ */
45
+ export interface ParsedRoute {
46
+ path: string;
47
+ /** 菜单显示名称 */
48
+ name: string;
49
+ icon: string;
50
+ /** 加载类型: internal(内部路由) | microapp(qiankun微应用) */
51
+ loadType: 'internal' | 'microapp';
52
+ /** 微应用入口 URL (htmlUrl 或 jsUrls[0]) */
53
+ entry?: string;
54
+ /** 原始页面配置 */
55
+ pageConfig?: PageConfig;
56
+ }
57
+
58
+ /**
59
+ * 解析后的菜单配置(用于渲染菜单组件)
60
+ */
61
+ export interface ParsedMenuItem {
62
+ key: string;
63
+ label: string;
64
+ icon: string;
65
+ type: MenuItemType;
66
+ path?: string;
67
+ children?: ParsedMenuItem[];
68
+ }
69
+
70
+ /**
71
+ * 主应用传递给子应用的 Props
72
+ */
73
+ export interface MicroAppProps {
74
+ /** 主应用标识 */
75
+ mainApp: '<%= projectName %>';
76
+ /** 共享的 request 实例,子应用可直接使用 */
77
+ request: <T = any>(url: string, options?: any) => Promise<T>;
78
+ }
79
+
80
+ /**
81
+ * Window 上挂载的菜单数据
82
+ */
83
+ declare global {
84
+ interface Window {
85
+ __MICO_MENUS__?: MenuItem[];
86
+ __MICO_CONFIG__?: {
87
+ appName?: string;
88
+ apiBaseUrl?: string;
89
+ [key: string]: unknown;
90
+ };
91
+ }
92
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * 请求客户端配置管理
3
+ */
4
+
5
+ import { getStoredAuthToken } from '../auth/cs-auth-manager';
6
+ import type { RequestClientOptions, TokenResolver } from './types';
7
+
8
+ const defaultClientOptions: RequestClientOptions = {
9
+ appId: process.env.APP_ID ?? '',
10
+ ticketParam: 'ticket',
11
+ logoutPath: '/logout',
12
+ apiBaseUrl: process.env.API_BASE_URL ?? '',
13
+ proxySuffix: process.env.PROXY_SUFFIX ?? '',
14
+ loginEndpoint: process.env.LOGIN_ENDPOINT ?? '',
15
+ refreshEndpoint: process.env.REFRESH_ENDPOINT ?? '',
16
+ externalLoginPath: process.env.EXTERNAL_LOGIN_PATH ?? '',
17
+ };
18
+
19
+ let clientOptions: RequestClientOptions = { ...defaultClientOptions };
20
+
21
+ let customAuthResolver: TokenResolver | undefined;
22
+
23
+ export const setAuthTokenResolver = (resolver: TokenResolver): void => {
24
+ customAuthResolver = resolver;
25
+ };
26
+
27
+ export const resolveAuthToken = (): string | undefined => {
28
+ if (customAuthResolver) {
29
+ return customAuthResolver();
30
+ }
31
+ return getStoredAuthToken();
32
+ };
33
+
34
+ export const configureRequestClient = (
35
+ overrides: Partial<RequestClientOptions>,
36
+ ): void => {
37
+ clientOptions = { ...clientOptions, ...overrides };
38
+ };
39
+
40
+ export const getClientOptions = (): RequestClientOptions => ({
41
+ ...clientOptions,
42
+ });
43
+
44
+ /** 解析 API 基础地址 */
45
+ export const resolveApiBaseUrl = (): string => {
46
+ return clientOptions.apiBaseUrl;
47
+ };
48
+
49
+ /** 解析登录端点 */
50
+ export const resolveLoginEndpoint = (): string => {
51
+ return clientOptions.loginEndpoint;
52
+ };
53
+
54
+ /** 解析刷新令牌端点 */
55
+ export const resolveRefreshEndpoint = (): string => {
56
+ return clientOptions.refreshEndpoint;
57
+ };
58
+
59
+ /** 解析外部登录路径 */
60
+ export const resolveExternalLoginPath = (): string => {
61
+ return clientOptions.externalLoginPath;
62
+ };
63
+
64
+ /** 获取 ticket 参数名 */
65
+ export const getTicketParam = (): string => {
66
+ return clientOptions.ticketParam;
67
+ };
68
+
69
+ /** 解析代理路径后缀 */
70
+ export const resolveProxySuffix = (proxySuffix?: string): string => {
71
+ if (proxySuffix) return proxySuffix;
72
+ return clientOptions.proxySuffix;
73
+ };
@@ -0,0 +1,188 @@
1
+ /**
2
+ * 统一请求模块
3
+ *
4
+ * 职责:
5
+ * - 提供统一的 request 函数
6
+ * - 导出配置和拦截器相关方法
7
+ *
8
+ * 模块拆分:
9
+ * - types.ts: 类型定义
10
+ * - config.ts: 配置管理
11
+ * - interceptors.ts: 拦截器管理
12
+ * - url-resolver.ts: URL 解析
13
+ * - token-refresh.ts: Token 刷新逻辑
14
+ * - sso.ts: SSO 认证逻辑
15
+ */
16
+
17
+ import { request as rawRequest } from '@umijs/max';
18
+ import { setStoredAuthToken } from '../auth/cs-auth-manager';
19
+ import { ROUTES } from '../constants';
20
+
21
+ // 配置相关
22
+ import {
23
+ configureRequestClient,
24
+ getClientOptions,
25
+ resolveAuthToken,
26
+ setAuthTokenResolver,
27
+ } from './config';
28
+
29
+ // 拦截器相关
30
+ import {
31
+ addRequestInterceptor,
32
+ addResponseInterceptor,
33
+ initDefaultInterceptors,
34
+ runRequestInterceptors,
35
+ runResponseInterceptors,
36
+ } from './interceptors';
37
+
38
+ // SSO 相关
39
+ import { ensureSsoSession, handleAuthFailureRedirect } from './sso';
40
+
41
+ // Token 刷新相关
42
+ import {
43
+ addToPendingQueue,
44
+ getRefreshPromise,
45
+ isFetchingToken,
46
+ shouldAttemptRefresh,
47
+ } from './token-refresh';
48
+
49
+ // 类型导出
50
+ import type {
51
+ RequestContext,
52
+ RequestInterceptor,
53
+ ResponseInterceptor,
54
+ UnifiedRequestOptions,
55
+ } from './types';
56
+
57
+ // URL 解析
58
+ import { resolveRequestUrl } from './url-resolver';
59
+
60
+ // 始终使用远程地址的路径
61
+ const ALWAYS_REMOTE_PATHS: string[] = [];
62
+
63
+ // 初始化默认拦截器
64
+ initDefaultInterceptors(isFetchingToken, addToPendingQueue);
65
+
66
+ /**
67
+ * 判断当前路由是否跳过认证
68
+ */
69
+ const shouldSkipAuth = (): boolean => {
70
+ return ROUTES.NO_AUTH_ROUTES.includes(location.pathname);
71
+ };
72
+
73
+ /**
74
+ * 统一请求函数
75
+ */
76
+ export const request = async <T = unknown>(
77
+ url: string,
78
+ options?: UnifiedRequestOptions,
79
+ ): Promise<T> => {
80
+ await ensureSsoSession();
81
+
82
+ const isAlwaysRemote = ALWAYS_REMOTE_PATHS.some((path) =>
83
+ url.startsWith(path),
84
+ );
85
+ const resolvedUrl = resolveRequestUrl(url, options, isAlwaysRemote);
86
+
87
+ const ctx: RequestContext = {
88
+ url: resolvedUrl,
89
+ options: options ?? {},
90
+ };
91
+
92
+ const next = await runRequestInterceptors(ctx);
93
+
94
+ const mergedHeaders: Record<string, string> = {
95
+ ...(next.options.headers || {}),
96
+ };
97
+
98
+ const resolvedToken = resolveAuthToken();
99
+ if (resolvedToken && !mergedHeaders.authtoken) {
100
+ mergedHeaders.authtoken = resolvedToken;
101
+ }
102
+
103
+ const normalizedOptions = {
104
+ ...next.options,
105
+ headers: mergedHeaders,
106
+ };
107
+
108
+ try {
109
+ const response = await rawRequest<T>(next.url, normalizedOptions);
110
+ return runResponseInterceptors(response, {
111
+ url: next.url,
112
+ options: normalizedOptions,
113
+ });
114
+ } catch (error) {
115
+ if (shouldAttemptRefresh(error) && !shouldSkipAuth()) {
116
+ const newToken = await getRefreshPromise();
117
+ if (newToken) {
118
+ setStoredAuthToken(newToken);
119
+ const retryHeaders = {
120
+ ...normalizedOptions.headers,
121
+ authtoken: newToken,
122
+ };
123
+ const retryOptions = {
124
+ ...normalizedOptions,
125
+ headers: retryHeaders,
126
+ };
127
+ const retryResponse = await rawRequest<T>(next.url, retryOptions);
128
+ return runResponseInterceptors(retryResponse, {
129
+ url: next.url,
130
+ options: retryOptions,
131
+ });
132
+ }
133
+ handleAuthFailureRedirect();
134
+ }
135
+ throw error;
136
+ }
137
+ };
138
+
139
+ /**
140
+ * 使用临时拦截器执行请求
141
+ */
142
+ export const withTemporaryInterceptors = async <T>(
143
+ runner: () => Promise<T>,
144
+ interceptors: {
145
+ request?: RequestInterceptor;
146
+ response?: ResponseInterceptor;
147
+ },
148
+ ): Promise<T> => {
149
+ const ejectors: Array<() => void> = [];
150
+
151
+ if (interceptors.request) {
152
+ ejectors.push(addRequestInterceptor(interceptors.request));
153
+ }
154
+ if (interceptors.response) {
155
+ ejectors.push(addResponseInterceptor(interceptors.response));
156
+ }
157
+
158
+ try {
159
+ return await runner();
160
+ } finally {
161
+ for (const eject of ejectors) {
162
+ eject();
163
+ }
164
+ }
165
+ };
166
+
167
+ // 导出配置相关方法
168
+ export {
169
+ configureRequestClient,
170
+ getClientOptions,
171
+ resolveAuthToken,
172
+ setAuthTokenResolver,
173
+ };
174
+
175
+ // 导出拦截器注册方法
176
+ export const registerRequestInterceptor = addRequestInterceptor;
177
+ export const registerResponseInterceptor = addResponseInterceptor;
178
+
179
+ // 导出认证相关方法
180
+ export { handleAuthFailureRedirect };
181
+
182
+ // 导出类型
183
+ export type {
184
+ RequestContext,
185
+ RequestInterceptor,
186
+ ResponseInterceptor,
187
+ UnifiedRequestOptions,
188
+ };