generator-mico-cli 0.2.21 → 0.2.22

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 (41) hide show
  1. package/generators/micro-react/templates/.cursor/rules/always-read-docs.mdc +14 -4
  2. package/generators/micro-react/templates/.cursor/rules/layout-app.mdc +36 -26
  3. package/generators/micro-react/templates/.cursor/rules/project-overview.mdc +5 -2
  4. package/generators/micro-react/templates/CLAUDE.md +4 -2
  5. package/generators/micro-react/templates/apps/layout/config/config.dev.ts +7 -3
  6. package/generators/micro-react/templates/apps/layout/config/routes.ts +0 -5
  7. 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 +5 -2
  8. 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 +107 -48
  9. 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
  10. package/generators/micro-react/templates/apps/layout/mock/menus.ts +89 -144
  11. package/generators/micro-react/templates/apps/layout/mock/pages.ts +83 -0
  12. package/generators/micro-react/templates/apps/layout/src/app.tsx +10 -8
  13. package/generators/micro-react/templates/apps/layout/src/common/menu/parser.ts +118 -43
  14. package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +31 -4
  15. package/generators/micro-react/templates/apps/layout/src/common/micro-prefetch.ts +3 -2
  16. package/generators/micro-react/templates/apps/layout/src/common/portal-data.ts +45 -0
  17. package/generators/micro-react/templates/apps/layout/src/common/request/config.ts +49 -10
  18. package/generators/micro-react/templates/apps/layout/src/common/request/interceptors.ts +1 -1
  19. package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +6 -0
  20. package/generators/micro-react/templates/apps/layout/src/common/theme.ts +0 -2
  21. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.less +0 -1
  22. package/generators/micro-react/templates/apps/layout/src/components/AppTabs/index.tsx +4 -4
  23. package/generators/micro-react/templates/apps/layout/src/components/IconFont/index.tsx +4 -5
  24. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +20 -1
  25. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +4 -3
  26. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/micro-app-manager.ts +7 -1
  27. package/generators/micro-react/templates/apps/layout/src/global.less +15 -2
  28. package/generators/micro-react/templates/apps/layout/src/hooks/useMenu.ts +3 -2
  29. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +30 -3
  30. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +15 -4
  31. package/generators/micro-react/templates/apps/layout/src/layouts/index.tsx +75 -38
  32. package/generators/micro-react/templates/apps/layout/src/pages/404/index.tsx +3 -7
  33. package/generators/micro-react/templates/apps/layout/src/services/user.ts +2 -2
  34. package/generators/micro-react/templates/dev.preset.json +1 -1
  35. package/generators/subapp-react/index.js +160 -2
  36. package/generators/subapp-react/templates/homepage/.env +2 -1
  37. package/generators/subapp-react/templates/homepage/config/config.dev.ts +1 -0
  38. package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +2 -1
  39. package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +2 -1
  40. package/generators/subapp-react/templates/homepage/config/config.prod.ts +2 -1
  41. package/package.json +1 -1
@@ -0,0 +1,179 @@
1
+ # 路由与菜单解耦
2
+
3
+ > 创建时间:2026-02-25
4
+
5
+ ## 功能概述
6
+
7
+ 将动态路由注册与菜单导航的数据源解耦。路由注册消费 `window.__MICO_PAGES__`(页面列表),菜单栏消费 `window.__MICO_MENUS__`(菜单树)。两者独立运作,权限通过菜单交叉引用 + 页面级兜底的双层策略控制。
8
+
9
+ ## 技术方案
10
+
11
+ ### 技术栈
12
+
13
+ - 框架:React 18 + @umijs/max
14
+ - 微前端:qiankun
15
+ - 状态管理:Umi initialState
16
+
17
+ ### 数据源关系
18
+
19
+ ```
20
+ __MICO_PAGES__ (扁平列表,所有页面)
21
+ ├── 菜单中的页面(一定能在 __MICO_MENUS__ 中找到对应菜单项)
22
+ └── 隐藏页面(不在菜单中显示,但路由可访问)
23
+
24
+ __MICO_MENUS__ (菜单树,用于导航)
25
+ └── page 字段 → 引用 __MICO_PAGES__ 中的某个页面
26
+ ```
27
+
28
+ ### 数据流
29
+
30
+ ```
31
+ Before:
32
+ patchClientRoutes ← extractRoutes(MENUS)
33
+ layouts 权限校验 ← extractRoutes(MENUS) + filterMenuItems(MENUS)
34
+ 菜单渲染 ← parseMenuItems(MENUS)
35
+
36
+ After:
37
+ patchClientRoutes ← getDynamicRoutes() → PAGES 优先,降级 MENUS
38
+ layouts 权限校验 ← getDynamicRoutes() + extractRoutes(MENUS) + filterMenuItems(MENUS)
39
+ 菜单渲染 ← parseMenuItems(MENUS) ← 不变
40
+ ```
41
+
42
+ ### 权限控制流程
43
+
44
+ ```
45
+ 用户访问路由
46
+
47
+
48
+ disableAuth / noPermissionRoute / superuser?
49
+ ├── 是 → 放行
50
+
51
+
52
+ page.accessControlEnabled === false?
53
+ ├── 是 → 跳过 SSO 认证 + 跳过权限校验(公开页面)
54
+
55
+
56
+ 非动态路由(不在 PAGES 中)?
57
+ ├── 是 → 交给 Umi 处理(404 等)
58
+
59
+
60
+ ┌─────────────────────────────────────────────┐
61
+ │ Tier 1: 菜单权限交叉引用 │
62
+ │ 页面在 __MICO_MENUS__ 中? │
63
+ │ ├── 是 → 沿用 sideMenus 白名单逻辑 │
64
+ │ │ 在 allowedMenuRoutes 中? │
65
+ │ │ ├── 是 → 放行 │
66
+ │ │ └── 否 → 403 │
67
+ │ └── 否 → 进入 Tier 2 │
68
+ ├─────────────────────────────────────────────┤
69
+ │ Tier 2: 隐藏页面级权限 │
70
+ │ (仅 PAGES 数据可用时生效) │
71
+ │ adminOnly: true → 403 │
72
+ │ accessControlEnabled: true │
73
+ │ → routeKey ∈ sideMenus ? 放行 : 403 │
74
+ │ 其他 → 放行 │
75
+ └─────────────────────────────────────────────┘
76
+ ```
77
+
78
+ ### 降级策略
79
+
80
+ 当 `window.__MICO_PAGES__` 未注入时(如旧版部署),`getDynamicRoutes()` 自动降级到从 `window.__MICO_MENUS__` 提取路由,行为与改动前完全一致。
81
+
82
+ ```
83
+ getDynamicRoutes():
84
+ hasWindowPages() ?
85
+ ├── 是 → extractRoutesFromPages(PAGES) ← 新逻辑
86
+ └── 否 → extractRoutes(MENUS) ← 旧逻辑,向后兼容
87
+ ```
88
+
89
+ ## 文件清单
90
+
91
+ ### 修改文件
92
+
93
+ | 文件路径 | 修改内容 |
94
+ | --- | --- |
95
+ | `src/common/menu/types.ts` | `PageConfig` 新增 `accessControlEnabled`、`routeKey` 字段;新增 `PublicPageItem` 类型(`Omit<PageConfig, ...>`);Window 声明新增 `__MICO_PAGES__` |
96
+ | `src/common/menu/parser.ts` | 新增 `getWindowPages`、`hasWindowPages`、`extractRoutesFromPages`、`getDynamicRoutes`、`findPageByPath` 函数;导出 `isSuperuserUser` |
97
+ | `src/app.tsx` | `patchClientRoutes` 改为调用 `getDynamicRoutes()` |
98
+ | `src/layouts/index.tsx` | 路由匹配改用 `allPageRoutes`;权限判断改为双层逻辑(菜单交叉引用 + 隐藏页面级兜底) |
99
+
100
+ ### 未修改文件
101
+
102
+ | 文件路径 | 说明 |
103
+ | --- | --- |
104
+ | `src/layouts/components/menu/index.tsx` | 菜单渲染逻辑不变,继续消费 `__MICO_MENUS__` |
105
+
106
+ ## API / 组件接口
107
+
108
+ ### PublicPageItem
109
+
110
+ ```typescript
111
+ type PublicPageItem = Omit<
112
+ PageConfig,
113
+ 'workspaceSubdomain' | 'publishedBy' | 'versions' | 'createdAt' | 'updatedAt'
114
+ >;
115
+ ```
116
+
117
+ `PageConfig` 新增字段:
118
+
119
+ | 字段 | 类型 | 说明 |
120
+ | --- | --- | --- |
121
+ | `accessControlEnabled` | `boolean` | 是否开启访问控制。`false` 时跳过 SSO 认证和权限校验(公开页面);`true` 时需要登录且通过 `routeKey` 校验权限 |
122
+ | `routeKey` | `string \| null` | 路由权限标识(用于匹配 sideMenus) |
123
+
124
+ ### 页面数据函数
125
+
126
+ ```typescript
127
+ /** 获取 window.__MICO_PAGES__ */
128
+ function getWindowPages(): PublicPageItem[];
129
+
130
+ /** 判断页面数据是否可用 */
131
+ function hasWindowPages(): boolean;
132
+
133
+ /** 从页面数据提取路由配置 */
134
+ function extractRoutesFromPages(pages: PublicPageItem[]): ParsedRoute[];
135
+
136
+ /** 获取动态路由(PAGES 优先,降级 MENUS) */
137
+ function getDynamicRoutes(): ParsedRoute[];
138
+
139
+ /** 根据路径查找页面配置(精确匹配 + 通配符) */
140
+ function findPageByPath(pages: PublicPageItem[], pathname: string): PublicPageItem | undefined;
141
+ ```
142
+
143
+ ### Window 全局变量
144
+
145
+ ```typescript
146
+ interface Window {
147
+ /** 页面列表 — 动态路由注册的数据源 */
148
+ __MICO_PAGES__?: PublicPageItem[];
149
+ /** 菜单树 — 菜单导航的数据源 */
150
+ __MICO_MENUS__?: MenuItem[];
151
+ }
152
+ ```
153
+
154
+ ## 设计决策
155
+
156
+ | 决策点 | 选择 | 理由 |
157
+ | --- | --- | --- |
158
+ | 路由数据源 | `__MICO_PAGES__` 独立于菜单 | 页面和菜单是不同维度:页面定义"有什么路由",菜单定义"导航怎么组织";解耦后支持隐藏页面 |
159
+ | 权限方案 | 菜单交叉引用 + 页面级兜底 | 菜单中的页面复用现有 sideMenus 白名单逻辑,改动最小;隐藏页面用 adminOnly + accessControlEnabled 兜底 |
160
+ | 降级策略 | `getDynamicRoutes()` 自动降级 | `__MICO_PAGES__` 未注入时回退到旧行为,零配置向后兼容 |
161
+ | PublicPageItem 定义 | `Omit<PageConfig, ...>` 派生 | 保持与 PageConfig 的类型继承关系,避免字段重复定义和类型漂移 |
162
+ | accessControlEnabled 语义 | `false` = 公开页面(跳过认证+授权),`true` = 需要权限检查 | 一个字段统一控制 SSO 认证、权限校验、子应用加载等待,减少配置冗余 |
163
+ | 隐藏页面权限 | 先 adminOnly 再 accessControlEnabled | adminOnly 是硬拦截,accessControlEnabled + routeKey 提供用户级粒度控制 |
164
+
165
+ ## 已知限制与待改进
166
+
167
+ - `routeKey` 当前复用 `sideMenus` 做权限匹配,后续可能独立为专门的权限字段
168
+ - 隐藏页面的权限控制依赖 `routeKey` 存在于 `sideMenus` 中,需要后端在下发用户权限时包含隐藏页面的 `routeKey`
169
+
170
+ ## 注意事项
171
+
172
+ - `__MICO_PAGES__` 只包含用户在后台配置的微应用页面,404/403 等静态页面不在其中
173
+ - `__MICO_MENUS__` 中菜单项的 `page` 字段引用的是 `__MICO_PAGES__` 中的某个页面
174
+ - 调试时可在控制台搜索 `isForbidden (menu check)` 或 `isForbidden (hidden page` 查看权限判断日志
175
+
176
+ ## 相关文档
177
+
178
+ - [微前端模式](./feature-微前端模式.md) - 微应用加载机制
179
+ - [菜单权限控制](./feature-菜单权限控制.md) - sideMenus 白名单权限逻辑
@@ -6,171 +6,116 @@
6
6
  * - id: 菜单唯一标识
7
7
  * - name: 菜单名称
8
8
  * - type: 'page' | 'group' (page: 页面, group: 分组)
9
- * - path: 路由路径 (group 类型为 null)
9
+ * - path: 路由路径 (type=page 时与 PAGES 中的 route 一致, group 类型为 null)
10
10
  * - icon: 图标名称
11
11
  * - enabled: 是否启用
12
12
  * - sortOrder: 排序权重
13
- * - pageId: 关联的页面 ID
14
- * - page: 页面配置 (微前端入口)
15
- * - htmlUrl: 子应用入口地址
16
- * - jsUrls: 额外 JS 资源
17
- * - cssUrls: 额外 CSS 资源
13
+ * - pageId: 关联的页面 ID (通过 pageId 与 __MICO_PAGES__ 关联)
18
14
  * - children: 子菜单数组
19
15
  */
20
16
 
21
- import type { MenuItem, PageConfig } from '@/common/menu/types';
17
+ import type { MenuItem } from '@/common/menu/types';
22
18
 
23
- /** Mock 页面配置 - 只需要核心字段 */
24
- type MockPageConfig = Pick<PageConfig,
25
- | 'id' | 'name' | 'route' | 'enabled' | 'htmlUrl' | 'jsUrls' | 'cssUrls'
26
- | 'adminOnly'
27
- >;
28
-
29
- /** Mock 菜单项 - page 字段使用简化类型,包含多语言字段 */
30
- type MockMenuItem = Omit<MenuItem, 'page' | 'children'> & {
31
- page: MockPageConfig | null;
19
+ /** Mock 菜单项 */
20
+ type MockMenuItem = Omit<MenuItem, 'children'> & {
32
21
  children: MockMenuItem[];
33
- /** 英文名称(用于英文环境权限匹配) */
34
- nameEn?: string;
35
- /** 菜单唯一标识符(用于权限匹配的兜底) */
36
- nameKey?: string;
37
22
  };
38
23
 
39
24
  const mockMenus: MockMenuItem[] = [
40
25
  {
41
- "id": 1,
42
- "name": "首页",
43
- "nameEn": "Home",
44
- "nameKey": "cs_web_menu_home",
45
- "type": "page",
46
- "path": null,
47
- "icon": "Home",
48
- "enabled": true,
49
- "sortOrder": 0,
50
- "pageId": 1,
51
- "page": {
52
- "id": 1,
53
- "name": "home",
54
- "route": "/",
55
- "enabled": true,
56
- "htmlUrl": "",
57
- "jsUrls": [],
58
- "cssUrls": []
59
- },
60
- "children": []
26
+ id: 1,
27
+ name: '首页',
28
+ nameEn: 'Home',
29
+ nameKey: 'cs_web_menu_home',
30
+ type: 'page',
31
+ path: '/',
32
+ icon: 'Home',
33
+ enabled: true,
34
+ sortOrder: 0,
35
+ pageId: 1,
36
+ children: [],
61
37
  },
62
38
  {
63
- "id": 2,
64
- "name": "示例模块",
65
- "nameEn": "Example Module",
66
- "nameKey": "cs_web_menu_example_module",
67
- "type": "group",
68
- "path": null,
69
- "icon": "List",
70
- "enabled": true,
71
- "sortOrder": 1,
72
- "pageId": null,
73
- "page": null,
74
- "children": [
39
+ id: 2,
40
+ name: '示例模块',
41
+ nameEn: 'Example Module',
42
+ nameKey: 'cs_web_menu_example_module',
43
+ type: 'group',
44
+ path: null,
45
+ icon: 'List',
46
+ enabled: true,
47
+ sortOrder: 1,
48
+ pageId: null,
49
+ children: [
75
50
  {
76
- "id": 3,
77
- "name": "示例页面",
78
- "nameEn": "Example Page",
79
- "nameKey": "cs_web_menu_example_page",
80
- "type": "page",
81
- "path": "/example/page",
82
- "icon": "File",
83
- "enabled": true,
84
- "sortOrder": 1,
85
- "pageId": 45,
86
- "page": {
87
- "id": 45,
88
- "name": "example-page",
89
- "route": "/example/page",
90
- "enabled": true,
91
- "htmlUrl": "",
92
- "jsUrls": [],
93
- "cssUrls": []
94
- },
95
- "children": []
96
- }
97
- ]
51
+ id: 3,
52
+ name: '示例页面',
53
+ nameEn: 'Example Page',
54
+ nameKey: 'cs_web_menu_example_page',
55
+ type: 'page',
56
+ path: '/example/page',
57
+ icon: 'File',
58
+ enabled: true,
59
+ sortOrder: 1,
60
+ pageId: 45,
61
+ children: [],
62
+ },
63
+ ],
98
64
  },
99
65
  {
100
- "id": 5,
101
- "name": "微应用示例",
102
- "nameEn": "Microapp Example",
103
- "nameKey": "cs_web_menu_microapp_example",
104
- "type": "group",
105
- "path": null,
106
- "icon": "Apps",
107
- "enabled": true,
108
- "sortOrder": 2,
109
- "pageId": null,
110
- "page": null,
111
- "children": [
66
+ id: 5,
67
+ name: '微应用示例',
68
+ nameEn: 'Microapp Example',
69
+ nameKey: 'cs_web_menu_microapp_example',
70
+ type: 'group',
71
+ path: null,
72
+ icon: 'Apps',
73
+ enabled: true,
74
+ sortOrder: 2,
75
+ pageId: null,
76
+ children: [
112
77
  {
113
- "id": 6,
114
- "name": "子应用页面",
115
- "nameEn": "Subapp Page",
116
- "nameKey": "cs_web_menu_subapp_page",
117
- "type": "page",
118
- "path": null,
119
- "icon": "Desktop",
120
- "enabled": true,
121
- "sortOrder": 1,
122
- "pageId": 55,
123
- "page": {
124
- "id": 55,
125
- "name": "subapp-example",
126
- "route": "/subapp",
127
- "enabled": true,
128
- "htmlUrl": "//localhost:8010",
129
- "jsUrls": [],
130
- "cssUrls": []
131
- },
132
- "children": []
133
- }
134
- ]
78
+ id: 6,
79
+ name: '子应用页面',
80
+ nameEn: 'Subapp Page',
81
+ nameKey: 'cs_web_menu_subapp_page',
82
+ type: 'page',
83
+ path: '/subapp/*',
84
+ icon: 'Desktop',
85
+ enabled: true,
86
+ sortOrder: 1,
87
+ pageId: 55,
88
+ children: [],
89
+ },
90
+ ],
135
91
  },
136
92
  {
137
- "id": 7,
138
- "name": "外部链接",
139
- "nameEn": "External Link",
140
- "nameKey": "cs_web_menu_external_link",
141
- "type": "link",
142
- "path": "https://github.com",
143
- "icon": "Link",
144
- "enabled": true,
145
- "sortOrder": 3,
146
- "pageId": null,
147
- "page": null,
148
- "children": []
93
+ id: 7,
94
+ name: '外部链接',
95
+ nameEn: 'External Link',
96
+ nameKey: 'cs_web_menu_external_link',
97
+ type: 'link',
98
+ path: 'https://github.com',
99
+ icon: 'Link',
100
+ enabled: true,
101
+ sortOrder: 3,
102
+ pageId: null,
103
+ children: [],
149
104
  },
150
105
  {
151
- "id": 8,
152
- "name": "权限管理",
153
- "nameEn": "Permission Management",
154
- "nameKey": "cs_web_menu_permission_management",
155
- "type": "page",
156
- "path": "/permission",
157
- "icon": "Permission",
158
- "enabled": true,
159
- "sortOrder": 3,
160
- "pageId": null,
161
- "adminOnly": true,
162
- "page": {
163
- "id": 8,
164
- "name": "permission",
165
- "route": "/permission",
166
- "enabled": true,
167
- "adminOnly": true,
168
- "htmlUrl": "https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.1/permission/index.html",
169
- "jsUrls": [],
170
- "cssUrls": []
171
- },
172
- "children": []
173
- }
174
- ]
106
+ id: 8,
107
+ name: '权限管理',
108
+ nameEn: 'Permission Management',
109
+ nameKey: 'cs_web_menu_permission_management',
110
+ type: 'page',
111
+ path: '/permission',
112
+ icon: 'Permission',
113
+ enabled: true,
114
+ sortOrder: 3,
115
+ pageId: null,
116
+ adminOnly: true,
117
+ children: [],
118
+ },
119
+ ];
175
120
 
176
121
  export default mockMenus;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Mock 页面数据
3
+ * 用于开发环境测试,模拟 window.__MICO_PAGES__ 数据
4
+ *
5
+ * 页面结构说明:
6
+ * - id: 页面唯一标识
7
+ * - name: 页面名称
8
+ * - route: 路由路径
9
+ * - htmlUrl: 微应用 HTML 入口 URL
10
+ * - jsUrls: 额外 JS 资源
11
+ * - cssUrls: 额外 CSS 资源
12
+ * - prefixPath: 路由前缀路径
13
+ * - routeMode: 路由匹配模式 (prefix | exact)
14
+ * - enabled: 是否启用
15
+ * - accessControlEnabled: 是否开启权限控制
16
+ * - adminOnly: 是否仅超级管理员可见
17
+ * - routeKey: 路由权限标识
18
+ * - mainDocumentId: 关联的主文档 ID
19
+ * - version: 当前版本号
20
+ */
21
+
22
+ import type { PublicPageItem } from '@/common/menu/types';
23
+
24
+ const mockPages: PublicPageItem[] = [
25
+ {
26
+ id: 125,
27
+ name: '登录页',
28
+ nameEn: 'Login',
29
+ nameKey: 'page.user.login',
30
+ route: '/user/login',
31
+ htmlUrl:
32
+ 'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.2/login/index.html',
33
+ jsUrls: [],
34
+ cssUrls: [],
35
+ prefixPath: '/user',
36
+ routeMode: 'exact',
37
+ enabled: true,
38
+ accessControlEnabled: false,
39
+ adminOnly: false,
40
+ routeKey: null,
41
+ mainDocumentId: 59,
42
+ version: 'v2026.02.26-04.21-000',
43
+ },
44
+ {
45
+ id: 124,
46
+ name: '权限管理',
47
+ nameEn: 'Permission Management',
48
+ nameKey: 'page.permission',
49
+ route: '/permission',
50
+ htmlUrl:
51
+ 'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.1/permission/index.html',
52
+ jsUrls: [],
53
+ cssUrls: [],
54
+ prefixPath: '',
55
+ routeMode: 'prefix',
56
+ enabled: true,
57
+ accessControlEnabled: true,
58
+ adminOnly: true,
59
+ routeKey: null,
60
+ mainDocumentId: 59,
61
+ version: 'v2026.02.26-04.13-419',
62
+ },
63
+ {
64
+ id: 115,
65
+ name: '兜底',
66
+ nameEn: 'Fallback',
67
+ nameKey: 'page.fallback',
68
+ route: '/*',
69
+ htmlUrl: '',
70
+ jsUrls: [],
71
+ cssUrls: [],
72
+ prefixPath: '',
73
+ routeMode: 'prefix',
74
+ enabled: true,
75
+ accessControlEnabled: false,
76
+ adminOnly: false,
77
+ routeKey: null,
78
+ mainDocumentId: 59,
79
+ version: 'v2026.01.26-14.25-095',
80
+ },
81
+ ];
82
+
83
+ export default mockPages;
@@ -4,12 +4,13 @@ import { errorConfig } from './requestErrorConfig';
4
4
  // 将 @mico-platform/ui 暴露到 window,供子应用 externals 使用
5
5
  import * as micoUI from '@mico-platform/ui';
6
6
  import React from 'react';
7
- import ReactDOM from 'react-dom/client';
7
+ import ReactDOM from 'react-dom';
8
+ import ReactDOMClient from 'react-dom/client';
8
9
 
9
10
  import { getStoredAuthToken } from './common/auth/auth-manager';
10
11
  import type { IUserInfo } from './common/auth/type';
11
12
  import { fetchUserInfo } from './services/user';
12
- import { extractRoutes, getWindowMenus } from './common/menu';
13
+ import { getDynamicRoutes, isPageAuthFree } from './common/menu';
13
14
  import {
14
15
  clearMicroAppProps,
15
16
  type IMicroAppProps,
@@ -23,6 +24,7 @@ import { initTheme } from './common/theme';
23
24
  import MicroAppLoader from './components/MicroAppLoader';
24
25
  import { isNoAuthRoute } from '@/constants';
25
26
  import { getCurrentLocale } from '@/common/locale';
27
+ import '@mico-platform/theme/dist/css/theme.css';
26
28
  import './global.less';
27
29
 
28
30
  // ==================== qiankun 全局错误处理 ====================
@@ -86,6 +88,7 @@ if (typeof window !== 'undefined') {
86
88
  const win = window as unknown as Record<string, unknown>;
87
89
  win.React = React;
88
90
  win.ReactDOM = ReactDOM;
91
+ win.ReactDOMClient = ReactDOMClient;
89
92
  win.micoUI = micoUI;
90
93
  }
91
94
 
@@ -127,9 +130,10 @@ export async function getInitialState(): Promise<{
127
130
 
128
131
  const { location } = history;
129
132
  const noAuthRoute = isNoAuthRoute(location.pathname);
133
+ const skipAuth = noAuthRoute || isPageAuthFree(location.pathname);
130
134
 
131
135
  // 非免认证路由:走 SSO 流程
132
- if (!noAuthRoute) {
136
+ if (!skipAuth) {
133
137
  await ensureSsoSession();
134
138
  }
135
139
 
@@ -145,7 +149,7 @@ export async function getInitialState(): Promise<{
145
149
  }
146
150
 
147
151
  // 非免认证路由且没有 token,跳转到 SSO 登录
148
- if (!noAuthRoute) {
152
+ if (!skipAuth) {
149
153
  handleAuthFailureRedirect();
150
154
  // 返回空状态,页面会被重定向
151
155
  return {
@@ -182,15 +186,13 @@ interface UmiRoute {
182
186
 
183
187
  /**
184
188
  * @name 动态路由配置
185
- * window.__MICO_MENUS__ 获取菜单数据,生成动态路由
189
+ * 优先从 window.__MICO_PAGES__ 获取页面数据,无数据时降级到 window.__MICO_MENUS__
186
190
  * @doc https://umijs.org/docs/max/router#%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1
187
191
  */
188
192
  export function patchClientRoutes({ routes }: { routes: UmiRoute[] }) {
189
- const menus = getWindowMenus();
190
- const dynamicRoutes = extractRoutes(menus);
193
+ const dynamicRoutes = getDynamicRoutes();
191
194
 
192
195
  console.log('[app.tsx] patchClientRoutes:', {
193
- menus,
194
196
  dynamicRoutes,
195
197
  routes,
196
198
  });