generator-mico-cli 0.1.28 → 0.2.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.
Files changed (64) hide show
  1. package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +1 -1
  2. package/generators/micro-react/templates/.cursor/rules/request-auth.mdc +2 -2
  3. package/generators/micro-react/templates/.cursor/rules/theme-system.mdc +2 -2
  4. package/generators/micro-react/templates/CLAUDE.md +27 -11
  5. package/generators/micro-react/templates/README.md +2 -0
  6. package/generators/micro-react/templates/apps/layout/config/config.dev.ts +11 -4
  7. package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +1 -11
  8. package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +0 -7
  9. package/generators/micro-react/templates/apps/layout/config/routes.ts +10 -0
  10. 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 +105 -0
  11. package/generators/micro-react/templates/apps/layout/docs/arch-/350/257/267/346/261/202/346/250/241/345/235/227.md +17 -15
  12. 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 +234 -0
  13. 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 +432 -0
  14. 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 +175 -0
  15. package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +15 -15
  16. package/generators/micro-react/templates/apps/layout/src/app.tsx +43 -28
  17. package/generators/micro-react/templates/apps/layout/src/common/auth/{cs-auth-manager.ts → auth-manager.ts} +6 -63
  18. package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +1 -1
  19. package/generators/micro-react/templates/apps/layout/src/common/auth/tool.ts +2 -3
  20. package/generators/micro-react/templates/apps/layout/src/common/auth/type.ts +38 -0
  21. package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +109 -2
  22. package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +74 -1
  23. package/generators/micro-react/templates/apps/layout/src/common/micro/index.ts +0 -8
  24. package/generators/micro-react/templates/apps/layout/src/common/micro/types.ts +0 -2
  25. package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +1 -1
  26. package/generators/micro-react/templates/apps/layout/src/common/request/index.ts +3 -11
  27. package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +2 -2
  28. package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +3 -2
  29. package/generators/micro-react/templates/apps/layout/src/common/request/token-refresh.ts +2 -2
  30. package/generators/micro-react/templates/apps/layout/src/common/request/url-resolver.ts +32 -48
  31. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +1 -1
  32. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +62 -14
  33. package/generators/micro-react/templates/apps/layout/src/global.less +5 -1
  34. package/generators/micro-react/templates/apps/layout/src/hooks/useAuth.ts +2 -3
  35. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.less +1 -1
  36. package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +17 -13
  37. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +1 -1
  38. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +11 -3
  39. package/generators/micro-react/templates/apps/layout/src/layouts/index.less +1 -1
  40. package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +52 -8
  41. package/generators/micro-react/templates/apps/layout/src/pages/403/index.tsx +28 -0
  42. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.less +275 -0
  43. package/generators/micro-react/templates/apps/layout/src/pages/User/Login/index.tsx +142 -0
  44. package/generators/micro-react/templates/apps/layout/src/services/auth.ts +1 -0
  45. package/generators/micro-react/templates/apps/layout/src/services/user.ts +25 -0
  46. package/generators/micro-react/templates/packages/shared-styles/README.md +16 -14
  47. package/generators/micro-react/templates/packages/shared-styles/arco-design-mobile-override.less +91 -0
  48. package/generators/micro-react/templates/packages/shared-styles/arco-override.less +41 -0
  49. package/generators/micro-react/templates/packages/shared-styles/index.d.ts +44 -0
  50. package/generators/micro-react/templates/packages/shared-styles/index.less +0 -1
  51. package/generators/micro-react/templates/packages/shared-styles/package.json +6 -3
  52. package/generators/micro-react/templates/packages/shared-styles/themes/dark/custom-var.less +118 -74
  53. package/generators/micro-react/templates/packages/shared-styles/themes/normal/custom-var.less +175 -101
  54. package/generators/micro-react/templates/packages/shared-styles/variables-only.less +357 -225
  55. package/generators/micro-react/templates/packages/shared-styles/variables.less +290 -201
  56. package/generators/subapp-react/templates/homepage/config/config.prod.ts +2 -2
  57. package/generators/subapp-react/templates/homepage/config/config.ts +6 -0
  58. package/generators/subapp-react/templates/homepage/mock/api.mock.ts +43 -43
  59. package/generators/subapp-react/templates/homepage/typings.d.ts +76 -0
  60. package/package.json +1 -1
  61. package/generators/micro-react/templates/apps/layout/src/styles/arco-override.less +0 -78
  62. package/generators/micro-react/templates/apps/layout/src/styles/themes/dark/custom-var.less +0 -244
  63. package/generators/micro-react/templates/apps/layout/src/styles/themes/normal/custom-var.less +0 -195
  64. package/generators/micro-react/templates/apps/layout/src/styles/variables.less +0 -5
@@ -3,14 +3,14 @@ import { prefetchApps } from 'qiankun';
3
3
  import { errorConfig } from './requestErrorConfig';
4
4
  // 解决「React19 中无法使用 Message/Notification」的问题。 @see https://github.com/arco-design/arco-design/issues/2900#issuecomment-2796571653
5
5
  import * as arco from '@arco-design/web-react';
6
- import '@arco-design/web-react/dist/css/arco.css';
7
- import '@arco-design/web-react/es/_util/react-19-adapter';
8
6
  import React from 'react';
9
7
  import ReactDOM from 'react-dom/client';
10
8
 
11
- import { getAuthInfo } from './common/auth/tool';
12
- import { NO_AUTH_ROUTE_LIST } from './constants';
9
+ import { getStoredAuthToken } from './common/auth/auth-manager';
10
+ import type { IUserInfo } from './common/auth/type';
11
+ import { fetchUserInfo } from './services/user';
13
12
  import { extractRoutes, getWindowMenus } from './common/menu';
13
+ import { ensureSsoSession } from './common/request/sso';
14
14
  import {
15
15
  clearMicroAppProps,
16
16
  type IMicroAppProps,
@@ -18,6 +18,7 @@ import {
18
18
  } from './common/micro';
19
19
  import { initTheme } from './common/theme';
20
20
  import MicroAppLoader from './components/MicroAppLoader';
21
+ import { NO_AUTH_ROUTE_LIST } from './constants';
21
22
  import './global.less';
22
23
 
23
24
  // ==================== 微应用预加载 ====================
@@ -104,38 +105,48 @@ initTheme();
104
105
  * @see https://umijs.org/docs/api/runtime-config#getinitialstate
105
106
  */
106
107
  export async function getInitialState(): Promise<{
107
- // FIXME: 待修改类型
108
108
  settings?: any;
109
- currentUser?: any;
109
+ currentUser?: IUserInfo;
110
110
  loading?: boolean;
111
- fetchUserInfo?: () => Promise<void>;
111
+ fetchUserInfo?: () => Promise<IUserInfo | null>;
112
112
  }> {
113
- const fetchUserInfo = async () => {};
114
- // 如果不是登录页面,执行
113
+ /**
114
+ * 获取用户信息
115
+ */
116
+ const fetchUserInfoFn = async (): Promise<IUserInfo | null> => {
117
+ try {
118
+ return await fetchUserInfo();
119
+ } catch (e) {
120
+ console.warn('[App] 获取用户信息失败', e);
121
+ return null;
122
+ }
123
+ };
124
+
115
125
  const { location } = history;
116
- if (
117
- !NO_AUTH_ROUTE_LIST.includes(
118
- location.pathname,
119
- )
120
- ) {
121
- const authInfo = getAuthInfo();
122
- const currentUser = {
123
- name: authInfo.nickname || '未知用户',
124
- avatar:
125
- authInfo.avatar ||
126
- 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
127
- userid: authInfo.uid,
128
- };
129
- return {
130
- fetchUserInfo,
131
- currentUser,
132
- };
126
+ const isNoAuthRoute = NO_AUTH_ROUTE_LIST.includes(location.pathname);
127
+
128
+ // 非免认证路由:走 SSO 流程
129
+ if (!isNoAuthRoute) {
130
+ await ensureSsoSession();
133
131
  }
132
+
133
+ // 有 token 就获取用户信息(无论在哪个页面,支持登录后 refresh 场景)
134
+ if (getStoredAuthToken()) {
135
+ const userInfo = await fetchUserInfoFn();
136
+ if (userInfo) {
137
+ return {
138
+ fetchUserInfo: fetchUserInfoFn,
139
+ currentUser: userInfo,
140
+ };
141
+ }
142
+ }
143
+
134
144
  return {
135
- fetchUserInfo,
145
+ fetchUserInfo: fetchUserInfoFn,
136
146
  };
137
147
  }
138
148
 
149
+
139
150
  /**
140
151
  * @name request 配置,可以配置错误处理
141
152
  * 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。
@@ -168,7 +179,11 @@ export function patchClientRoutes({ routes }: { routes: UmiRoute[] }) {
168
179
  const menus = getWindowMenus();
169
180
  const dynamicRoutes = extractRoutes(menus);
170
181
 
171
- console.log('[app.tsx] patchClientRoutes:', { menus, dynamicRoutes, routes });
182
+ console.log('[app.tsx] patchClientRoutes:', {
183
+ menus,
184
+ dynamicRoutes,
185
+ routes,
186
+ });
172
187
 
173
188
  // 找到根路由(全局布局)
174
189
  const rootRoute = routes.find((r) => r.path === '/');
@@ -16,20 +16,16 @@ export interface IAuthInfo {
16
16
  nickname: string;
17
17
  uid: string;
18
18
  token: string;
19
- wsToken: string;
20
19
  refreshToken: string;
21
20
  }
22
21
 
23
22
  /**
24
- * Mibot Token 信息类型
23
+ * 用户信息类型(yufu_login 接口返回)
25
24
  */
26
- interface MibotTokenInfo {
27
- token?: string;
28
- staff_uid?: string;
29
- staff_prop?: {
30
- avatar?: string;
31
- nickname?: string;
32
- };
25
+ interface YufuUserInfo {
26
+ user_name?: string;
27
+ email?: string;
28
+ avatar?: string;
33
29
  }
34
30
 
35
31
  /**
@@ -38,14 +34,13 @@ interface MibotTokenInfo {
38
34
  interface AuthResponseData {
39
35
  access?: string;
40
36
  refresh?: string;
41
- mibot_token_info?: MibotTokenInfo;
37
+ user_info?: YufuUserInfo;
42
38
  }
43
39
 
44
40
  interface AuthResponse {
45
41
  code?: number;
46
42
  data?: AuthResponseData;
47
43
  refresh?: string;
48
- mibot_token_info?: MibotTokenInfo;
49
44
  }
50
45
 
51
46
  /**
@@ -64,14 +59,6 @@ export const getStoredRefreshToken = (): string | undefined => {
64
59
  return getFromStorage(REFRESH_TOKEN_KEY) ?? undefined;
65
60
  };
66
61
 
67
- /**
68
- * 获取存储的 WebSocket token
69
- * @returns WebSocket token,如果不存在则返回 undefined
70
- */
71
- export const getStoredWsToken = (): string | undefined => {
72
- return getFromStorage(WS_TOKEN_KEY) ?? undefined;
73
- };
74
-
75
62
  /**
76
63
  * 设置存储的认证 token
77
64
  * @param token - 认证 token,如果为 null 或 undefined 则删除
@@ -96,18 +83,6 @@ export const setStoredRefreshToken = (token?: string | null): void => {
96
83
  setStorage(REFRESH_TOKEN_KEY, token);
97
84
  };
98
85
 
99
- /**
100
- * 设置存储的 WebSocket token
101
- * @param token - WebSocket token,如果为 null 或 undefined 则删除
102
- */
103
- export const setStoredWsToken = (token?: string | null): void => {
104
- if (!token) {
105
- removeStorage(WS_TOKEN_KEY);
106
- return;
107
- }
108
- setStorage(WS_TOKEN_KEY, token);
109
- };
110
-
111
86
  /**
112
87
  * 清除所有存储的认证相关 token 和信息
113
88
  */
@@ -130,7 +105,6 @@ export const getAuthInfo = (): IAuthInfo => {
130
105
  nickname: getFromStorage(NICKNAME) || '',
131
106
  uid: getFromStorage(UID) || '',
132
107
  token: getFromStorage(AUTH_TOKEN_KEY) || '',
133
- wsToken: getFromStorage(WS_TOKEN_KEY) || '',
134
108
  refreshToken: getFromStorage(REFRESH_TOKEN_KEY) || '',
135
109
  };
136
110
  };
@@ -152,32 +126,11 @@ export const setAuthInfo = (info: IAuthInfo): void => {
152
126
  if (info.token) {
153
127
  setStorage(AUTH_TOKEN_KEY, info.token);
154
128
  }
155
- if (info.wsToken) {
156
- setStorage(WS_TOKEN_KEY, info.wsToken);
157
- }
158
129
  if (info.refreshToken) {
159
130
  setStorage(REFRESH_TOKEN_KEY, info.refreshToken);
160
131
  }
161
132
  };
162
133
 
163
- /**
164
- * 持久化 Mibot Token 信息(提取的公共函数)
165
- */
166
- const persistMibotTokenInfo = (mibotTokenInfo: MibotTokenInfo): void => {
167
- if (mibotTokenInfo.token) {
168
- setStoredWsToken(mibotTokenInfo.token);
169
- }
170
- if (mibotTokenInfo.staff_uid) {
171
- setStorage(UID, mibotTokenInfo.staff_uid);
172
- }
173
- if (mibotTokenInfo.staff_prop?.avatar) {
174
- setStorage(AVATAR, mibotTokenInfo.staff_prop.avatar);
175
- }
176
- if (mibotTokenInfo.staff_prop?.nickname) {
177
- setStorage(NICKNAME, mibotTokenInfo.staff_prop.nickname);
178
- }
179
- };
180
-
181
134
  /**
182
135
  * 从响应数据中持久化 token 信息
183
136
  * 支持多种响应格式:
@@ -194,13 +147,6 @@ export const maybePersistTokens = (payload: AuthResponse | null): void => {
194
147
  if (refresh) {
195
148
  setStoredRefreshToken(refresh);
196
149
  }
197
-
198
- const mibotTokenInfo =
199
- payload.mibot_token_info ?? payload.data?.mibot_token_info;
200
- if (mibotTokenInfo) {
201
- console.info('设置用户TOKEN信息', mibotTokenInfo);
202
- persistMibotTokenInfo(mibotTokenInfo);
203
- }
204
150
  }
205
151
 
206
152
  // 处理 code === 200 格式的响应(登录接口)
@@ -213,8 +159,5 @@ export const maybePersistTokens = (payload: AuthResponse | null): void => {
213
159
  if (data.refresh) {
214
160
  setStoredRefreshToken(data.refresh);
215
161
  }
216
- if (data.mibot_token_info) {
217
- persistMibotTokenInfo(data.mibot_token_info);
218
- }
219
162
  }
220
163
  };
@@ -1,7 +1,7 @@
1
1
  import { authLogger } from '@/common/logger';
2
2
  import { checkStaffAuth } from '@/services/auth';
3
3
  import { handleAuthFailureRedirect } from '../request';
4
- import { clearStoredTokens, getAuthInfo } from './cs-auth-manager';
4
+ import { clearStoredTokens, getAuthInfo } from './auth-manager';
5
5
 
6
6
  export function logout(): void {
7
7
  clearStoredTokens();
@@ -1,3 +1,2 @@
1
- // localStorage 相关的认证函数已迁移到 @/common/auth/cs-auth-manager
2
- // 重新导出以保持向后兼容
3
- export { getAuthInfo, setAuthInfo, type IAuthInfo } from './cs-auth-manager';
1
+ export { getAuthInfo, setAuthInfo } from './auth-manager';
2
+ export type { IAuthInfo } from './auth-manager';
@@ -7,3 +7,41 @@ export const UID = 'uid';
7
7
 
8
8
  /** 微应用模式下主应用传递的环境标识 */
9
9
  export const MICRO_ENV_KEY = 'micro_env';
10
+
11
+ /**
12
+ * 权限树节点
13
+ */
14
+ export interface IPermissionNode {
15
+ id: number;
16
+ name: string;
17
+ sort: number;
18
+ level: number;
19
+ parent: number | null;
20
+ codename: string;
21
+ sub_menu?: IPermissionNode[];
22
+ }
23
+
24
+ /**
25
+ * 完整用户信息(/api/user/info 接口返回的 data 字段)
26
+ */
27
+ export interface IUserInfo {
28
+ id: number;
29
+ username: string;
30
+ email: string;
31
+ user_name: string;
32
+ avatar: string;
33
+ phone: string;
34
+ first_name: string;
35
+ last_name: string;
36
+ is_superuser: boolean;
37
+ is_staff: boolean;
38
+ is_active: boolean;
39
+ type: number;
40
+ agency_id: number;
41
+ last_login: string;
42
+ permission_tree: IPermissionNode[];
43
+ miss_permissions: string[];
44
+ side_menus: string[];
45
+ app_permissions: string[];
46
+ groups: string[];
47
+ }
@@ -4,7 +4,111 @@ import type { MenuItem, ParsedMenuItem, ParsedRoute } from './types';
4
4
  * 获取 window 上挂载的菜单数据
5
5
  */
6
6
  export const getWindowMenus = (): MenuItem[] => {
7
- return window.__MICO_MENUS__ || [];
7
+ if (typeof window === 'undefined') return [];
8
+ const menus = window.__MICO_MENUS__;
9
+ return Array.isArray(menus) ? menus : [];
10
+ };
11
+
12
+ export interface MenuFilterOptions {
13
+ /** 是否是超级用户 */
14
+ isSuperuser?: boolean | number;
15
+ /** 允许访问的菜单路径列表(白名单) */
16
+ sideMenus?: string[];
17
+ }
18
+
19
+ const isSuperuserUser = (value?: boolean | number): boolean => {
20
+ return value === true || value === 1;
21
+ };
22
+
23
+ export const buildMenuPath = (parentPath: string, name: string): string => {
24
+ return parentPath ? `${parentPath}.${name}` : name;
25
+ };
26
+
27
+ /**
28
+ * 检查菜单路径是否允许访问(白名单逻辑)
29
+ * - 超级用户可以访问所有菜单
30
+ * - 非超级用户不能访问"权限管理"
31
+ * - 菜单路径在 sideMenus 中,或是 sideMenus 中某项的前缀(父级菜单)
32
+ */
33
+ const isMenuAllowed = (
34
+ menuPath: string,
35
+ options: MenuFilterOptions,
36
+ ): boolean => {
37
+ // 超级用户可以访问所有菜单
38
+ if (isSuperuserUser(options.isSuperuser)) return true;
39
+
40
+ // 非超级用户不能访问"权限管理"
41
+ if (menuPath === '权限管理') return false;
42
+
43
+ const sideMenus = options.sideMenus || [];
44
+
45
+ // 如果没有配置 sideMenus,非超级用户没有任何菜单权限
46
+ if (sideMenus.length === 0) return false;
47
+
48
+ // 检查是否在白名单中(精确匹配或前缀匹配)
49
+ return sideMenus.some((allowedPath) => {
50
+ // 精确匹配:菜单路径完全等于白名单中的路径
51
+ if (menuPath === allowedPath) return true;
52
+ // 前缀匹配:白名单路径以菜单路径开头(说明菜单是父级)
53
+ if (allowedPath.startsWith(menuPath + '.')) return true;
54
+ return false;
55
+ });
56
+ };
57
+
58
+ export const isRouteAllowed = (
59
+ menuPath: string,
60
+ options: MenuFilterOptions = {},
61
+ ): boolean => {
62
+ return isMenuAllowed(menuPath, options);
63
+ };
64
+
65
+ /**
66
+ * 根据权限过滤菜单项(白名单逻辑)
67
+ */
68
+ export const filterMenuItems = (
69
+ items: MenuItem[],
70
+ options: MenuFilterOptions = {},
71
+ parentPath = '',
72
+ ): MenuItem[] => {
73
+ return items
74
+ .filter((item) => item.enabled)
75
+ .map((item) => {
76
+ const menuPath = buildMenuPath(parentPath, item.name);
77
+ const isAllowed = isMenuAllowed(menuPath, options);
78
+
79
+ // 递归处理子菜单
80
+ const nextChildren = item.children?.length
81
+ ? filterMenuItems(item.children, options, menuPath)
82
+ : [];
83
+
84
+ // 分组类型:如果没有子菜单,不显示
85
+ if (item.type === 'group' && nextChildren.length === 0) {
86
+ return null;
87
+ }
88
+
89
+ // 当前菜单不允许访问
90
+ if (!isAllowed) {
91
+ // 但如果有允许的子菜单,仍需显示当前菜单作为容器
92
+ if (nextChildren.length > 0) {
93
+ return { ...item, children: nextChildren };
94
+ }
95
+ return null;
96
+ }
97
+
98
+ // 当前菜单允许访问
99
+ const hasChildren = (item.children?.length || 0) > 0;
100
+ if (!hasChildren) {
101
+ return item;
102
+ }
103
+
104
+ // 有子菜单但过滤后为空,不显示
105
+ if (nextChildren.length === 0) {
106
+ return null;
107
+ }
108
+
109
+ return { ...item, children: nextChildren };
110
+ })
111
+ .filter((item): item is MenuItem => Boolean(item));
8
112
  };
9
113
 
10
114
  /**
@@ -38,10 +142,13 @@ const getEntry = (page: MenuItem['page']): string | undefined => {
38
142
  export const extractRoutes = (
39
143
  items: MenuItem[],
40
144
  routes: ParsedRoute[] = [],
145
+ parentPath = '',
41
146
  ): ParsedRoute[] => {
42
147
  for (const item of items) {
43
148
  if (!item.enabled) continue;
44
149
 
150
+ const menuPath = buildMenuPath(parentPath, item.name);
151
+
45
152
  if (item.type === 'page' && item.page && item.page.enabled) {
46
153
  const loadType = getLoadType(item.page);
47
154
  routes.push({
@@ -55,7 +162,7 @@ export const extractRoutes = (
55
162
  }
56
163
 
57
164
  if (item.children && item.children.length > 0) {
58
- extractRoutes(item.children, routes);
165
+ extractRoutes(item.children, routes, menuPath);
59
166
  }
60
167
  }
61
168
 
@@ -1,18 +1,43 @@
1
+ /**
2
+ * 页面路由匹配模式
3
+ */
4
+ export type PageRouteMode = 'prefix' | 'exact';
5
+
1
6
  /**
2
7
  * 页面配置 - 从统一中台获取
3
8
  */
4
9
  export interface PageConfig {
5
10
  id: number;
11
+ /** 页面名称 */
6
12
  name: string;
7
13
  /** 路由路径 */
8
14
  route: string;
15
+ /** 是否启用 */
9
16
  enabled: boolean;
10
17
  /** 微应用 HTML 入口 URL (用于 qiankun 加载) */
11
- htmlUrl: string | null;
18
+ htmlUrl: string;
12
19
  /** 微应用 JS 入口 URL 列表 */
13
20
  jsUrls: string[];
14
21
  /** 微应用 CSS URL 列表 */
15
22
  cssUrls: string[];
23
+ /** 路由前缀路径 */
24
+ prefixPath: string;
25
+ /** 路由匹配模式 */
26
+ routeMode: PageRouteMode;
27
+ /** 关联的主文档 ID */
28
+ mainDocumentId: number;
29
+ /** 所属工作空间子域名 */
30
+ workspaceSubdomain: string;
31
+ /** 当前版本号 */
32
+ version: string;
33
+ /** 历史版本列表 */
34
+ versions: string[];
35
+ /** 发布者邮箱 */
36
+ publishedBy: string;
37
+ /** 创建时间 */
38
+ createdAt: string;
39
+ /** 更新时间 */
40
+ updatedAt: string;
16
41
  }
17
42
 
18
43
  /**
@@ -77,6 +102,50 @@ export interface MicroAppProps {
77
102
  request: <T = any>(url: string, options?: any) => Promise<T>;
78
103
  }
79
104
 
105
+ /**
106
+ * 工作空间渲染模式
107
+ */
108
+ export type WorkspaceRenderMode = 'micro-frontend' | 'default';
109
+
110
+ /**
111
+ * 工作空间状态
112
+ */
113
+ export type WorkspaceStatus = 'active' | 'inactive' | 'pending';
114
+
115
+ /**
116
+ * 工作空间配置 - 从统一中台获取
117
+ */
118
+ export interface WorkspaceConfig {
119
+ /** 关联的应用 ID(可能为空) */
120
+ appId: number | null;
121
+ /** 创建时间 */
122
+ createdAt: string;
123
+ /** 创建者 ID */
124
+ createdBy: number;
125
+ /** 描述信息 */
126
+ description: string;
127
+ /** 首页路径 */
128
+ homePath: string;
129
+ /** 最后更新时间 */
130
+ lastUpdate: string;
131
+ /** 工作空间名称 */
132
+ name: string;
133
+ /** 生产环境域名 */
134
+ productionDomain: string;
135
+ /** 渲染模式 */
136
+ renderMode: WorkspaceRenderMode;
137
+ /** 仓库地址 */
138
+ repository: string;
139
+ /** 是否启用 SSO */
140
+ ssoEnabled: boolean;
141
+ /** 状态 */
142
+ status: WorkspaceStatus;
143
+ /** 子域名标识 */
144
+ subdomain: string;
145
+ /** 测试环境域名 */
146
+ testDomain: string;
147
+ }
148
+
80
149
  /**
81
150
  * Window 上挂载的菜单数据
82
151
  */
@@ -88,5 +157,9 @@ declare global {
88
157
  apiBaseUrl?: string;
89
158
  [key: string]: unknown;
90
159
  };
160
+ __MICO_WORKSPACE__?: WorkspaceConfig | null;
161
+ __MICO_PAGE__?: PageConfig | null;
162
+ /** qiankun 注入的全局变量,表示当前运行在 qiankun 子应用环境中 */
163
+ __POWERED_BY_QIANKUN__?: boolean;
91
164
  }
92
165
  }
@@ -32,13 +32,6 @@ export type {
32
32
  MicroAppErrorSource,
33
33
  } from './types';
34
34
 
35
- declare global {
36
- interface Window {
37
- /** qiankun 注入的全局变量,表示当前运行在 qiankun 子应用环境中 */
38
- __POWERED_BY_QIANKUN__?: boolean;
39
- }
40
- }
41
-
42
35
  // ============================================
43
36
  // 环境检测
44
37
  // ============================================
@@ -140,7 +133,6 @@ export const setMicroAppProps = (props: IMicroAppProps): void => {
140
133
  // 1. 存储认证信息到 localStorage(复用现有的 setAuthInfo)
141
134
  setAuthInfo({
142
135
  token: props.authToken || '',
143
- wsToken: props.wsToken || '',
144
136
  uid: props.uid || '',
145
137
  avatar: props.avatar || '',
146
138
  nickname: props.nickname || '',
@@ -124,8 +124,6 @@ export interface IMicroAppProps {
124
124
  authToken?: string;
125
125
  /** CDN 文件的前缀 host */
126
126
  filehost?: string;
127
- /** WebSocket 建立连接的 Authorization */
128
- wsToken?: string;
129
127
  /** 用户头像 URL */
130
128
  avatar?: string;
131
129
  /** 当前客服 ID */
@@ -2,7 +2,7 @@
2
2
  * 请求客户端配置管理
3
3
  */
4
4
 
5
- import { getStoredAuthToken } from '../auth/cs-auth-manager';
5
+ import { getStoredAuthToken } from '../auth/auth-manager';
6
6
  import type { RequestClientOptions, TokenResolver } from './types';
7
7
 
8
8
  const defaultClientOptions: RequestClientOptions = {
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  import { request as rawRequest } from '@umijs/max';
18
- import { setStoredAuthToken } from '../auth/cs-auth-manager';
18
+ import { setStoredAuthToken } from '../auth/auth-manager';
19
19
  import { ROUTES } from '../constants';
20
20
 
21
21
  // 配置相关
@@ -36,7 +36,7 @@ import {
36
36
  } from './interceptors';
37
37
 
38
38
  // SSO 相关
39
- import { ensureSsoSession, handleAuthFailureRedirect } from './sso';
39
+ import { handleAuthFailureRedirect } from './sso';
40
40
 
41
41
  // Token 刷新相关
42
42
  import {
@@ -57,9 +57,6 @@ import type {
57
57
  // URL 解析
58
58
  import { resolveRequestUrl } from './url-resolver';
59
59
 
60
- // 始终使用远程地址的路径
61
- const ALWAYS_REMOTE_PATHS: string[] = [];
62
-
63
60
  // 初始化默认拦截器
64
61
  initDefaultInterceptors(isFetchingToken, addToPendingQueue);
65
62
 
@@ -77,12 +74,7 @@ export const request = async <T = unknown>(
77
74
  url: string,
78
75
  options?: UnifiedRequestOptions,
79
76
  ): 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);
77
+ const resolvedUrl = resolveRequestUrl(url, options);
86
78
 
87
79
  const ctx: RequestContext = {
88
80
  url: resolvedUrl,
@@ -4,8 +4,8 @@
4
4
 
5
5
  import { getFromStorage, safeParseJSON } from '@/common/helpers';
6
6
  import { Message } from '@arco-design/web-react';
7
- import { maybePersistTokens } from '../auth/cs-auth-manager';
8
- import { UID } from '../auth/type';
7
+ import { maybePersistTokens } from '@/common/auth/auth-manager';
8
+ import { UID } from '@/common/auth/type';
9
9
  import { getClientOptions, resolveAuthToken } from './config';
10
10
  import type {
11
11
  RequestContext,
@@ -6,7 +6,8 @@ import { request as rawRequest } from '@umijs/max';
6
6
  import {
7
7
  maybePersistTokens,
8
8
  setStoredAuthToken,
9
- } from '../auth/cs-auth-manager';
9
+ } from '@/common/auth/auth-manager';
10
+ import { ROUTES } from '@/common/constants';
10
11
  import {
11
12
  getTicketParam,
12
13
  resolveAuthToken,
@@ -49,7 +50,7 @@ export const handleAuthFailureRedirect = (): void => {
49
50
  const serviceUrl = redirectUrl.toString();
50
51
 
51
52
  window.location.href = `${
52
- externalLoginPath ?? '/login'
53
+ externalLoginPath ?? ROUTES.LOGIN
53
54
  }?service=${encodeURIComponent(serviceUrl)}`;
54
55
  } else {
55
56
  console.warn('认证失败,但已达到最大重定向次数,停止重定向');
@@ -8,7 +8,7 @@ import {
8
8
  maybePersistTokens,
9
9
  setStoredAuthToken,
10
10
  setStoredRefreshToken,
11
- } from '../auth/cs-auth-manager';
11
+ } from '@/common/auth/auth-manager';
12
12
  import { resolveRefreshEndpoint } from './config';
13
13
  import type { PendingRequest, RequestContext } from './types';
14
14
 
@@ -130,7 +130,7 @@ export const shouldAttemptRefresh = (error: unknown): boolean => {
130
130
  if (error && typeof error === 'object' && 'response' in error) {
131
131
  const typedError = error as { response?: { status?: number } };
132
132
  const status = typedError.response?.status;
133
- return status === 401 || status === 403;
133
+ return status === 401;
134
134
  }
135
135
  return false;
136
136
  };