generator-mico-cli 0.2.22 → 0.2.23

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 (42) hide show
  1. package/README.md +33 -0
  2. package/bin/mico.js +15 -2
  3. package/generators/micro-react/index.js +44 -6
  4. package/generators/micro-react/meta.json +2 -1
  5. package/generators/micro-react/templates/_gitignore +3 -1
  6. package/generators/micro-react/templates/_npmrc +1 -0
  7. package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +5 -0
  8. package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +5 -0
  9. package/generators/micro-react/templates/apps/layout/config/config.prod.ts +12 -0
  10. 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 +0 -1
  11. 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 +9 -8
  12. package/generators/micro-react/templates/apps/layout/mock/api.mock.ts +81 -61
  13. package/generators/micro-react/templates/apps/layout/mock/pages.ts +3 -3
  14. package/generators/micro-react/templates/apps/layout/package.json +1 -0
  15. package/generators/micro-react/templates/apps/layout/src/app.tsx +5 -2
  16. package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.less +1 -5
  17. package/generators/micro-react/templates/apps/layout/src/components/RightContent/AvatarDropdown.tsx +12 -16
  18. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.less +2 -1
  19. package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +7 -8
  20. package/generators/micro-react/templates/apps/layout/src/services/user.ts +5 -1
  21. package/generators/micro-react/templates/package.json +1 -0
  22. package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +45 -0
  23. package/generators/subapp-react/index.js +46 -4
  24. package/generators/subapp-react/templates/homepage/config/config.dev.ts +0 -1
  25. package/generators/subapp-react/templates/homepage/config/config.prod.development.ts +2 -2
  26. package/generators/subapp-react/templates/homepage/config/config.prod.testing.ts +2 -2
  27. package/generators/subapp-react/templates/homepage/config/config.prod.ts +9 -2
  28. package/generators/subapp-react/templates/homepage/package.json +1 -0
  29. package/generators/subapp-react/templates/homepage/src/app.tsx +6 -0
  30. package/generators/subapp-umd/ignore-list.json +5 -0
  31. package/generators/subapp-umd/index.js +325 -0
  32. package/generators/subapp-umd/meta.json +11 -0
  33. package/generators/subapp-umd/templates/README.md +94 -0
  34. package/generators/subapp-umd/templates/package.json +35 -0
  35. package/generators/subapp-umd/templates/public/index.html +34 -0
  36. package/generators/subapp-umd/templates/src/App.less +15 -0
  37. package/generators/subapp-umd/templates/src/App.tsx +13 -0
  38. package/generators/subapp-umd/templates/src/index.ts +2 -0
  39. package/generators/subapp-umd/templates/tsconfig.json +27 -0
  40. package/generators/subapp-umd/templates/webpack.config.js +68 -0
  41. package/lib/utils.js +2 -1
  42. package/package.json +1 -1
package/README.md CHANGED
@@ -9,6 +9,7 @@
9
9
  | [docs/mico-cli.md](docs/mico-cli.md) | Mico CLI 功能概述与技术方案 |
10
10
  | [docs/micro-react-generator.md](docs/micro-react-generator.md) | Monorepo 项目生成器说明 |
11
11
  | [docs/subapp-react-generator.md](docs/subapp-react-generator.md) | React 子应用生成器说明 |
12
+ | [docs/subapp-umd-generator.md](docs/subapp-umd-generator.md) | UMD 组件包生成器说明 |
12
13
 
13
14
  ## 要求
14
15
 
@@ -97,6 +98,7 @@ mico create micro-react
97
98
  - @mico-platform/ui、@mico-platform/theme
98
99
  - Turborepo + pnpm Workspace
99
100
  - Husky + Commitlint
101
+ - @common-web/sentry 错误监控与 SourceMap 上传
100
102
 
101
103
  ## React 子应用生成器
102
104
 
@@ -108,6 +110,34 @@ cd <monorepo-root>
108
110
  mico create subapp-react
109
111
  ```
110
112
 
113
+ ## UMD 组件包生成器
114
+
115
+ 在 Monorepo 的 `packages/` 目录下创建 UMD 格式的组件包,使用 Webpack 构建。适用于通过 `<script>` 标签加载的场景(如主应用菜单挂载组件、第三方系统嵌入 Widget 等)。
116
+
117
+ ```bash
118
+ cd <monorepo-root>
119
+ mico create subapp-umd
120
+ ```
121
+
122
+ 生成器会提示输入:
123
+ - **Package name** — 包名(如 `my-widget`)
124
+ - **UMD global variable name** — 全局变量名(如 `MyWidget`)
125
+ - **Package scope** — 包作用域(自动从根 `package.json` 检测)
126
+ - **Dev server port** — 开发端口(默认 `9100`)
127
+
128
+ 生成的包支持:
129
+ - `pnpm dev` — 启动 webpack-dev-server,同时提供 HTML 预览页和 UMD JS 文件
130
+ - `pnpm build` — 构建生产环境 UMD 产物到 `dist/`
131
+
132
+ 开发模式下:
133
+
134
+ | URL | 用途 |
135
+ |---|---|
136
+ | `http://localhost:<port>/` | HTML 预览页,独立调试 |
137
+ | `http://localhost:<port>/<name>.umd.js` | UMD JS 文件,供主应用通过 `jsUrls` 联调 |
138
+
139
+ DevTools Sources 面板中可在 `webpack://<name>/src/` 下定位原始 TypeScript 源码进行断点调试。
140
+
111
141
  ## 本地调试
112
142
 
113
143
  克隆项目后,执行以下步骤进行本地开发和调试:
@@ -133,6 +163,9 @@ mico create micro-react
133
163
 
134
164
  # 测试 subapp-react 生成器(需在已有 monorepo 中执行)
135
165
  mico create subapp-react
166
+
167
+ # 测试 subapp-umd 生成器(需在已有 monorepo 中执行)
168
+ mico create subapp-umd
136
169
  ```
137
170
 
138
171
  调试完成后,可以取消全局链接:
package/bin/mico.js CHANGED
@@ -29,12 +29,14 @@ Options:
29
29
  --version, -v Show version number
30
30
  --verbose Show detailed output during generation
31
31
  --dry-run Preview files without creating them
32
+ --force Overwrite all existing files without confirmation
32
33
  --no-update-check Skip update check
33
34
 
34
35
  Examples:
35
36
  mico create subapp-react
36
37
  mico create micro-react --verbose
37
38
  mico create micro-react --dry-run
39
+ mico create micro-react --force
38
40
  mico list
39
41
  mico update
40
42
  mico doctor
@@ -350,6 +352,7 @@ function performUpdate(latestVersion) {
350
352
  * @param {object} options - 选项
351
353
  * @param {boolean} options.verbose - 是否启用详细输出
352
354
  * @param {boolean} options.dryRun - 是否启用 dry-run 模式
355
+ * @param {boolean} options.force - 是否强制覆盖已有文件
353
356
  */
354
357
  function runGenerator(generator, rest, passthroughArgs, options = {}) {
355
358
  const localGeneratorEntry = path.join(
@@ -374,6 +377,10 @@ function runGenerator(generator, rest, passthroughArgs, options = {}) {
374
377
  yoArgs.push('--dry-run');
375
378
  }
376
379
 
380
+ if (options.force) {
381
+ yoArgs.push('--force');
382
+ }
383
+
377
384
  if (passthroughArgs.length > 0) {
378
385
  yoArgs.push('--', ...passthroughArgs);
379
386
  }
@@ -394,6 +401,9 @@ function runGenerator(generator, rest, passthroughArgs, options = {}) {
394
401
  if (options.dryRun) {
395
402
  console.log(' \x1b[2m[verbose] Dry-run mode enabled\x1b[0m');
396
403
  }
404
+ if (options.force) {
405
+ console.log(' \x1b[2m[verbose] Force mode enabled\x1b[0m');
406
+ }
397
407
  console.log('');
398
408
  }
399
409
 
@@ -432,6 +442,7 @@ async function main() {
432
442
  const skipUpdateCheck = mainArgs.includes('--no-update-check');
433
443
  const isVerbose = mainArgs.includes('--verbose');
434
444
  const isDryRun = mainArgs.includes('--dry-run');
445
+ const isForce = mainArgs.includes('--force');
435
446
 
436
447
  // 过滤掉标志参数
437
448
  const filteredArgs = mainArgs.filter(
@@ -442,7 +453,8 @@ async function main() {
442
453
  arg !== '-v' &&
443
454
  arg !== '--no-update-check' &&
444
455
  arg !== '--verbose' &&
445
- arg !== '--dry-run'
456
+ arg !== '--dry-run' &&
457
+ arg !== '--force'
446
458
  );
447
459
 
448
460
  // 处理 --version
@@ -514,7 +526,8 @@ async function main() {
514
526
  // 运行生成器
515
527
  runGenerator(generator, rest.slice(1), passthroughArgs, {
516
528
  verbose: isVerbose,
517
- dryRun: isDryRun
529
+ dryRun: isDryRun,
530
+ force: isForce
518
531
  });
519
532
  return;
520
533
  }
@@ -36,9 +36,9 @@ module.exports = class extends Generator {
36
36
  this.logger.verbose('Config:', JSON.stringify(rcConfig, null, 2));
37
37
  }
38
38
 
39
- // 检查当前目录是否已是一个 monorepo
39
+ // 检查当前目录是否已是一个 monorepo(--force 跳过此检查)
40
40
  const workspaceFile = path.join(this.projectRoot, 'pnpm-workspace.yaml');
41
- if (fs.existsSync(workspaceFile)) {
41
+ if (fs.existsSync(workspaceFile) && !this.options.force) {
42
42
  console.error('');
43
43
  console.error('❌ Error: Current directory is already a monorepo.');
44
44
  console.error('');
@@ -51,6 +51,9 @@ module.exports = class extends Generator {
51
51
  console.error(' mkdir my-project && cd my-project');
52
52
  console.error(' mico create micro-react');
53
53
  console.error('');
54
+ console.error(' To regenerate in an existing monorepo, use --force:');
55
+ console.error(' mico create micro-react --force');
56
+ console.error('');
54
57
  process.exit(1);
55
58
  }
56
59
  }
@@ -278,9 +281,31 @@ module.exports = class extends Generator {
278
281
 
279
282
  this.log('');
280
283
  this.log('📦 正在安装依赖...');
281
- this.spawnCommandSync('pnpm', ['install'], {
282
- cwd: this.destDir,
283
- });
284
+ try {
285
+ this.spawnCommandSync('pnpm', ['install'], {
286
+ cwd: this.destDir,
287
+ });
288
+ } catch (e) {
289
+ this._installFailed = true;
290
+ this.log('');
291
+ this.log('⚠️ 依赖安装失败,但项目文件已全部生成。');
292
+ this.logger.verbose('Install error:', e.message);
293
+ return;
294
+ }
295
+
296
+ // 依赖安装成功后,格式化生成的文件以消除风格差异
297
+ const layoutDir = path.join(this.destDir, 'apps/layout');
298
+ if (fs.existsSync(path.join(layoutDir, '.prettierrc'))) {
299
+ this.log('');
300
+ this.log('🎨 格式化生成的文件...');
301
+ try {
302
+ this.spawnCommandSync('pnpm', ['-C', 'apps/layout', 'format'], {
303
+ cwd: this.destDir,
304
+ });
305
+ } catch (e) {
306
+ this.logger.verbose('Formatting failed (non-critical):', e.message);
307
+ }
308
+ }
284
309
  }
285
310
 
286
311
  end() {
@@ -288,7 +313,20 @@ module.exports = class extends Generator {
288
313
  if (this._skipInstall) return;
289
314
 
290
315
  this.log('');
291
- this.log('✅ 项目创建成功!');
316
+
317
+ if (this._installFailed) {
318
+ this.log('⚠️ 项目文件已创建,但依赖安装未完成。');
319
+ this.log('');
320
+ this.log(' 请手动安装依赖:');
321
+ this.log('');
322
+ this.log(' pnpm install');
323
+ this.log('');
324
+ this.log(' 如果安装仍然失败,可尝试:');
325
+ this.log(' pnpm install --network-concurrency 4');
326
+ } else {
327
+ this.log('✅ 项目创建成功!');
328
+ }
329
+
292
330
  this.log('');
293
331
  this.log(' 后续步骤:');
294
332
  this.log('');
@@ -7,6 +7,7 @@
7
7
  "qiankun 微前端架构",
8
8
  "Arco Design + Tailwind CSS",
9
9
  "主题切换、国际化、认证模块",
10
- "可配置 CDN 路径前缀(支持多业务线隔离)"
10
+ "可配置 CDN 路径前缀(支持多业务线隔离)",
11
+ "Sentry 错误监控与 SourceMap 上传"
11
12
  ]
12
13
  }
@@ -56,4 +56,6 @@ build
56
56
 
57
57
  **/tasks/*
58
58
 
59
- .pnpm-store/**
59
+ .pnpm-store/**
60
+
61
+ .worktrees/**
@@ -1,5 +1,6 @@
1
1
  registry=https://registry.npmjs.com/
2
2
  @mico-platform:registry=https://nexus-vywrajy.micoworld.net/repository/mico-base-common/
3
+ @common-web:registry=https://nexus-vywrajy.micoworld.net/repository/mico-base-common/
3
4
  package-lock=false
4
5
  //nexus-vywrajy.micoworld.net/repository/mico-base-common/:_auth=bWljby1ucG06SDR4WUROazdad1NeczltblJMTw==
5
6
 
@@ -3,6 +3,11 @@
3
3
  import { defineConfig } from '@umijs/max';
4
4
 
5
5
  const config: ReturnType<typeof defineConfig> = {
6
+ externals: {
7
+ react: 'React',
8
+ 'react-dom': 'ReactDOM',
9
+ '@common-web/sentry': 'CommonWebSentry',
10
+ },
6
11
  define: {
7
12
  'process.env.NODE_ENV': 'development',
8
13
  'process.env.APP_ID': '<%= projectName %>',
@@ -3,6 +3,11 @@
3
3
  import { defineConfig } from '@umijs/max';
4
4
 
5
5
  const config: ReturnType<typeof defineConfig> = {
6
+ externals: {
7
+ react: 'React',
8
+ 'react-dom': 'ReactDOM',
9
+ '@common-web/sentry': 'CommonWebSentry',
10
+ },
6
11
  define: {
7
12
  'process.env.NODE_ENV': 'testing',
8
13
  'process.env.APP_ID': '<%= projectName %>',
@@ -1,6 +1,7 @@
1
1
  // https://umijs.org/config/
2
2
 
3
3
  import { defineConfig } from '@umijs/max';
4
+ import { applySentryPlugin } from '../../../scripts/apply-sentry-plugin';
4
5
  const { CDN_PUBLIC_PATH } = process.env;
5
6
 
6
7
  const PUBLIC_PATH: string = CDN_PUBLIC_PATH
@@ -8,6 +9,11 @@ const PUBLIC_PATH: string = CDN_PUBLIC_PATH
8
9
  : '/layout/';
9
10
 
10
11
  const config: ReturnType<typeof defineConfig> = {
12
+ /**
13
+ * 启用 Source Map(用于 Sentry 错误追踪)
14
+ * hidden-source-map 会生成 .map 文件但不在 JS 中添加 sourcemap 注释
15
+ */
16
+ devtool: 'hidden-source-map',
11
17
  define: {
12
18
  'process.env.NODE_ENV': 'production',
13
19
  'process.env.APP_ID': '<%= projectName %>',
@@ -20,6 +26,11 @@ const config: ReturnType<typeof defineConfig> = {
20
26
  'process.env.EXTERNAL_LOGIN_PATH':
21
27
  'https://micous-idp.cig.tencentcs.com/sso/xxxxxxx/cas',
22
28
  },
29
+ externals: {
30
+ react: 'React',
31
+ 'react-dom': 'ReactDOM',
32
+ '@common-web/sentry': 'CommonWebSentry',
33
+ },
23
34
  // 生产环境:将所有代码打包到一个文件
24
35
  extraBabelPlugins: ['babel-plugin-dynamic-import-node'],
25
36
 
@@ -29,6 +40,7 @@ const config: ReturnType<typeof defineConfig> = {
29
40
  memo.optimization.splitChunks(false);
30
41
  // 禁用 runtimeChunk
31
42
  memo.optimization.runtimeChunk(false);
43
+ applySentryPlugin({ memo, appName: 'layout' });
32
44
  return memo;
33
45
  },
34
46
  publicPath: PUBLIC_PATH,
@@ -334,7 +334,6 @@ const config: ReturnType<typeof defineConfig> = {
334
334
  externals: {
335
335
  react: 'window.React',
336
336
  'react-dom': 'window.ReactDOM',
337
- 'react-dom/client': 'window.ReactDOMClient',
338
337
  '@mico-platform/ui': 'window.micoUI',
339
338
  },
340
339
  };
@@ -64,12 +64,13 @@
64
64
  └──────────────────────────────────────────┘
65
65
 
66
66
 
67
- ┌─────────────────────────────────┐
68
- │ 3. 菜单渲染 (menu/index.tsx)
69
- isNoPermissionRoute(pathname)?
70
- ├── 是 → 显示全部菜单
71
- └── 按 side_menus 过滤
72
- └─────────────────────────────────┘
67
+ ┌──────────────────────────────────────────┐
68
+ │ 3. 菜单渲染 (menu/index.tsx)
69
+ 按 side_menus 过滤 │
70
+ 每个菜单项独立检查 isNoPermissionRoute
71
+ ├── 匹配该项始终显示
72
+ │ └── 不匹配 → 按 sideMenus 白名单过滤 │
73
+ └──────────────────────────────────────────┘
73
74
 
74
75
 
75
76
  ┌──────────────────────────────────────────────┐
@@ -99,7 +100,7 @@ page.accessControlEnabled === false?
99
100
 
100
101
 
101
102
  是否在 noPermissionRouteList 中?
102
- ├── 是 → 允许访问,显示全部菜单
103
+ ├── 是 → 允许访问,菜单按各项独立判断
103
104
 
104
105
 
105
106
  是否是非动态路由(不在 PAGES 中)?
@@ -344,7 +345,7 @@ if (!isAuthReady) {
344
345
  | 403 处理 | 原地渲染组件 | 保持 URL 不变,用户体验更好,便于分享链接 |
345
346
  | 父级菜单显示 | 前缀匹配 | 子菜单有权限时,父级菜单需要作为容器显示 |
346
347
  | 超级用户 | 跳过所有检查 | 管理员需要完整访问权限 |
347
- | 免权限路由的菜单 | 显示全部 | 用户访问公开页面时应能看到所有导航选项 |
348
+ | 免权限路由的菜单 | 按菜单项独立判断 | 每个菜单项根据自身路由是否匹配 noPermissionRouteList 独立决定显示,避免菜单随当前页面变化 |
348
349
  | 免认证路由的子应用 | 直接加载 | 不等待 currentUser,免认证路由本身不需要登录 |
349
350
  | 免权限路由的子应用 | 直接加载 | 不等待 currentUser,避免加载卡住 |
350
351
  | 静态路由不受权限控制 | 默认允许访问 | 见下方"静态路由与动态路由"说明 |
@@ -6,73 +6,93 @@
6
6
 
7
7
  export default {
8
8
  // 获取用户信息
9
- // 'GET /api/user/info': {
9
+ 'GET /api/user/info': {
10
+ "code": 200,
11
+ "data": {
12
+ "id": 381,
13
+ "last_login": "2026-03-06T02:37:10.050735Z",
14
+ "is_superuser": true,
15
+ "username": "本地测试mock用户",
16
+ "first_name": "",
17
+ "last_name": "",
18
+ "email": "本地测试mock用户@micous.com",
19
+ "is_staff": true,
20
+ "is_active": true,
21
+ "type": 1,
22
+ "phone": "",
23
+ "agency_id": 0,
24
+ "avatar": "https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png",
25
+ "user_name": "Easton",
26
+ "permission_tree": [
27
+ ],
28
+ "miss_permissions": [],
29
+ "side_menus": [
30
+ '首页',
31
+ '示例模块.示例页面',
32
+ '微应用示例.子应用页面',
33
+ '外部链接',
34
+ '权限管理',
35
+ ],
36
+ "region_permissions": []
37
+ },
38
+ "msg": "ok"
39
+ },
40
+
41
+ // 获取统计数据
42
+ // 'GET /api/dashboard/stats': {
10
43
  // success: true,
11
44
  // data: {
12
- // id: 1001,
13
- // name: '张三',
14
- // email: 'zhangsan@example.com',
15
- // avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=homepage',
16
- // role: 'admin',
17
- // department: '技术部',
45
+ // totalUsers: 12580,
46
+ // activeUsers: 3420,
47
+ // pendingTasks: 156,
48
+ // completedTasks: 8934,
49
+ // lastUpdated: new Date().toISOString(),
18
50
  // },
19
51
  // },
20
52
 
21
- // 获取统计数据
22
- 'GET /api/dashboard/stats': {
23
- success: true,
24
- data: {
25
- totalUsers: 12580,
26
- activeUsers: 3420,
27
- pendingTasks: 156,
28
- completedTasks: 8934,
29
- lastUpdated: new Date().toISOString(),
30
- },
31
- },
32
-
33
53
  // 获取列表数据
34
- 'GET /api/items': {
35
- success: true,
36
- data: {
37
- list: [
38
- {
39
- id: 1,
40
- title: '待审核内容 A',
41
- status: 'pending',
42
- createdAt: '2025-12-27 10:00:00',
43
- },
44
- {
45
- id: 2,
46
- title: '待审核内容 B',
47
- status: 'pending',
48
- createdAt: '2025-12-27 09:30:00',
49
- },
50
- {
51
- id: 3,
52
- title: '已通过内容 C',
53
- status: 'approved',
54
- createdAt: '2025-12-26 15:00:00',
55
- },
56
- {
57
- id: 4,
58
- title: '已拒绝内容 D',
59
- status: 'rejected',
60
- createdAt: '2025-12-26 14:00:00',
61
- },
62
- ],
63
- total: 4,
64
- page: 1,
65
- pageSize: 10,
66
- },
67
- },
54
+ // 'GET /api/items': {
55
+ // success: true,
56
+ // data: {
57
+ // list: [
58
+ // {
59
+ // id: 1,
60
+ // title: '待审核内容 A',
61
+ // status: 'pending',
62
+ // createdAt: '2025-12-27 10:00:00',
63
+ // },
64
+ // {
65
+ // id: 2,
66
+ // title: '待审核内容 B',
67
+ // status: 'pending',
68
+ // createdAt: '2025-12-27 09:30:00',
69
+ // },
70
+ // {
71
+ // id: 3,
72
+ // title: '已通过内容 C',
73
+ // status: 'approved',
74
+ // createdAt: '2025-12-26 15:00:00',
75
+ // },
76
+ // {
77
+ // id: 4,
78
+ // title: '已拒绝内容 D',
79
+ // status: 'rejected',
80
+ // createdAt: '2025-12-26 14:00:00',
81
+ // },
82
+ // ],
83
+ // total: 4,
84
+ // page: 1,
85
+ // pageSize: 10,
86
+ // },
87
+ // },
68
88
 
69
89
  // POST 请求示例
70
- 'POST /api/items/approve': (req: any, res: any) => {
71
- const { id } = req.body || {};
72
- res.json({
73
- success: true,
74
- message: `Item ${id} approved successfully`,
75
- data: { id, status: 'approved' },
76
- });
77
- },
90
+ // 'POST /api/items/approve': (req: any, res: any) => {
91
+ // const { id } = req.body || {};
92
+ // res.json({
93
+ // success: true,
94
+ // message: `Item ${id} approved successfully`,
95
+ // data: { id, status: 'approved' },
96
+ // });
97
+ // },
78
98
  };
@@ -29,7 +29,7 @@ const mockPages: PublicPageItem[] = [
29
29
  nameKey: 'page.user.login',
30
30
  route: '/user/login',
31
31
  htmlUrl:
32
- 'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.2/login/index.html',
32
+ 'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.4/login/index.html',
33
33
  jsUrls: [],
34
34
  cssUrls: [],
35
35
  prefixPath: '/user',
@@ -48,7 +48,7 @@ const mockPages: PublicPageItem[] = [
48
48
  nameKey: 'page.permission',
49
49
  route: '/permission',
50
50
  htmlUrl:
51
- 'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.1/permission/index.html',
51
+ 'https://cdn-portal.micoplatform.com/portal-center/common-web/0.0.4/permission/index.html',
52
52
  jsUrls: [],
53
53
  cssUrls: [],
54
54
  prefixPath: '',
@@ -72,7 +72,7 @@ const mockPages: PublicPageItem[] = [
72
72
  prefixPath: '',
73
73
  routeMode: 'prefix',
74
74
  enabled: true,
75
- accessControlEnabled: false,
75
+ accessControlEnabled: true,
76
76
  adminOnly: false,
77
77
  routeKey: null,
78
78
  mainDocumentId: 59,
@@ -32,6 +32,7 @@
32
32
  "spark-md5": "^3.0.2"
33
33
  },
34
34
  "devDependencies": {
35
+ "@common-web/sentry": "^0.0.3",
35
36
  "@types/react": "^18.0.33",
36
37
  "@types/react-dom": "^18.0.11",
37
38
  "@types/spark-md5": "^3.0.5",
@@ -1,11 +1,11 @@
1
1
  import { history, type RequestConfig } from '@umijs/max';
2
2
  import { addGlobalUncaughtErrorHandler } from 'qiankun';
3
+ import { SentryErrorBoundary } from '@common-web/sentry';
3
4
  import { errorConfig } from './requestErrorConfig';
4
5
  // 将 @mico-platform/ui 暴露到 window,供子应用 externals 使用
5
6
  import * as micoUI from '@mico-platform/ui';
6
7
  import React from 'react';
7
8
  import ReactDOM from 'react-dom';
8
- import ReactDOMClient from 'react-dom/client';
9
9
 
10
10
  import { getStoredAuthToken } from './common/auth/auth-manager';
11
11
  import type { IUserInfo } from './common/auth/type';
@@ -88,7 +88,6 @@ if (typeof window !== 'undefined') {
88
88
  const win = window as unknown as Record<string, unknown>;
89
89
  win.React = React;
90
90
  win.ReactDOM = ReactDOM;
91
- win.ReactDOMClient = ReactDOMClient;
92
91
  win.micoUI = micoUI;
93
92
  }
94
93
 
@@ -172,6 +171,10 @@ export const request: RequestConfig = {
172
171
  ...errorConfig,
173
172
  };
174
173
 
174
+ export function rootContainer(container: React.ReactNode) {
175
+ return <SentryErrorBoundary>{container}</SentryErrorBoundary>;
176
+ }
177
+
175
178
  /**
176
179
  * Umi 路由类型定义
177
180
  */
@@ -11,14 +11,10 @@
11
11
  }
12
12
 
13
13
  .micro-app-loading {
14
- position: absolute;
15
- top: 0;
16
- left: 0;
17
- right: 0;
18
- bottom: 0;
19
14
  display: flex;
20
15
  align-items: center;
21
16
  justify-content: center;
17
+ min-height: 600px;
22
18
  background: var(--color-bg-1);
23
19
  z-index: 10;
24
20
  }
@@ -1,4 +1,5 @@
1
1
  import { logout, STORAGE_KEYS } from '@/common/auth';
2
+ import type { IUserInfo } from '@/common/auth/type';
2
3
  import {
3
4
  getCurrentTimezone,
4
5
  getTimezoneRegion,
@@ -39,13 +40,10 @@ interface IMenuItem {
39
40
  children?: IMenuItem[];
40
41
  }
41
42
 
42
- const DEFAULT_AVATAR =
43
- 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png';
44
-
45
43
  // TODO: 临时假数据,后续接入真实登录态
46
- const MOCK_USER = {
44
+ const MOCK_USER: Partial<IUserInfo> = {
47
45
  user_name: 'Test User',
48
- avatar: DEFAULT_AVATAR,
46
+ username: 'test@micous.com',
49
47
  };
50
48
 
51
49
  export const AvatarName: React.FC<{ userName?: string }> = ({ userName }) => {
@@ -100,11 +98,11 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
100
98
 
101
99
  // 管理头像 URL
102
100
  const [avatarSrc, setAvatarSrc] = useState<string>(
103
- currentUser?.avatar || DEFAULT_AVATAR,
101
+ currentUser?.avatar || '',
104
102
  );
105
103
 
106
104
  useEffect(() => {
107
- setAvatarSrc(currentUser?.avatar || DEFAULT_AVATAR);
105
+ setAvatarSrc(currentUser?.avatar || '');
108
106
  }, [currentUser?.avatar]);
109
107
 
110
108
  // 加载时区列表
@@ -142,10 +140,6 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
142
140
  };
143
141
  }, []);
144
142
 
145
- const handleAvatarError = () => {
146
- setAvatarSrc(DEFAULT_AVATAR);
147
- };
148
-
149
143
  const loginOut = async () => {
150
144
  logout();
151
145
  const { search, pathname } = window.location;
@@ -370,11 +364,13 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
370
364
  }
371
365
  >
372
366
  <div className="flex items-center avatar-dropdown-trigger">
373
- <div className="flex items-center">
374
- <Avatar size={24} shape="circle">
375
- <img src={avatarSrc} alt="avatar" onError={handleAvatarError} />
376
- </Avatar>
377
- </div>
367
+ {avatarSrc && (
368
+ <div className="flex items-center">
369
+ <Avatar size={24} shape="circle">
370
+ <img src={avatarSrc} alt="avatar" />
371
+ </Avatar>
372
+ </div>
373
+ )}
378
374
  <AvatarName userName={currentUser?.user_name} />
379
375
  <IconFont
380
376
  type="webcs-outline_down1"
@@ -135,11 +135,12 @@
135
135
  }
136
136
 
137
137
  // Sider styles
138
- .<%= projectName %>-sider {
138
+ .layout-web-sider {
139
139
  box-shadow: none;
140
140
  background-color: @color-text-5 !important;
141
141
  position: fixed !important;
142
142
  height: calc(100vh - @header-height) !important;
143
+ z-index: 999;
143
144
 
144
145
  .arco-layout-sider-trigger {
145
146
  display: flex;