generator-mico-cli 0.2.11 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,6 +67,39 @@ cd <monorepo-root>
67
67
  mico create subapp-react
68
68
  ```
69
69
 
70
+ ## 本地调试
71
+
72
+ 克隆项目后,执行以下步骤进行本地开发和调试:
73
+
74
+ ```bash
75
+ # 1. 安装依赖
76
+ pnpm install
77
+
78
+ # 2. 将本地包链接到全局(需要先安装 yo)
79
+ npm install -g yo
80
+ npm link
81
+
82
+ # 3. 验证链接成功
83
+ mico --version
84
+ ```
85
+
86
+ 链接成功后,`mico` 命令会使用本地代码,可以直接修改代码并测试:
87
+
88
+ ```bash
89
+ # 测试 micro-react 生成器
90
+ mkdir test-project && cd test-project
91
+ mico create micro-react
92
+
93
+ # 测试 subapp-react 生成器(需在已有 monorepo 中执行)
94
+ mico create subapp-react
95
+ ```
96
+
97
+ 调试完成后,可以取消全局链接:
98
+
99
+ ```bash
100
+ npm unlink -g generator-mico-cli
101
+ ```
102
+
70
103
  ## 同步子应用模板
71
104
 
72
105
  将源项目的 `apps/homepage` 同步到生成器模板目录:
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ # 计算当前构建分支的 BASE_REF,并为 Turbo 增量构建准备 TURBO_FILTER
4
+ # 该脚本会被其他脚本 source 调用,不要在这里直接 exit 1
5
+
6
+ set -e
7
+
8
+ # 获取项目根目录(如果调用方已设置 PROJECT_ROOT,则使用;否则使用当前工作目录)
9
+ PROJECT_ROOT="${PROJECT_ROOT:-$(pwd)}"
10
+
11
+ # 获取当前构建的分支(去掉 origin/ 前缀,用于比较)
12
+ # 优先使用环境变量 CURRENT_BRANCH(Jenkins 传入,格式可能是 origin/main、origin/feat/xxx)
13
+ # 其次使用 BRANCH_OR_TAG,最后从 git 获取
14
+ if [ -n "${CURRENT_BRANCH}" ]; then
15
+ CURRENT_BRANCH_NAME="${CURRENT_BRANCH#origin/}" # 去掉 origin/ 前缀
16
+ elif [ -n "${BRANCH_OR_TAG}" ]; then
17
+ CURRENT_BRANCH_NAME="${BRANCH_OR_TAG#origin/}" # 去掉 origin/ 前缀
18
+ else
19
+ CURRENT_BRANCH_NAME="$(git rev-parse --abbrev-ref HEAD)"
20
+ fi
21
+
22
+ echo "[before_build] Current branch (without origin/): ${CURRENT_BRANCH_NAME}"
23
+
24
+ # 比较当前分支和上次成功构建的分支是否一致
25
+ # LAST_SUCCESS_BRANCH 由 Jenkins 在构建时设置(从上次构建的结果中获取,格式可能是 origin/main、origin/feat/xxx)
26
+ if [ -n "${LAST_SUCCESS_BRANCH}" ]; then
27
+ # 去掉 LAST_SUCCESS_BRANCH 的 origin/ 前缀,用于比较
28
+ LAST_SUCCESS_BRANCH_NAME="${LAST_SUCCESS_BRANCH#origin/}"
29
+ echo "[before_build] Last success branch (without origin/): ${LAST_SUCCESS_BRANCH_NAME}"
30
+
31
+ if [ "${CURRENT_BRANCH_NAME}" != "${LAST_SUCCESS_BRANCH_NAME}" ]; then
32
+ # 分支不一致,需要全量构建
33
+ echo "[before_build] Branch changed: ${LAST_SUCCESS_BRANCH_NAME} -> ${CURRENT_BRANCH_NAME}, will perform full build (no filter)"
34
+ unset TURBO_FILTER
35
+ else
36
+ # 分支一致,尝试使用 PREVIOUS_COMMIT 进行增量构建
37
+ echo "[before_build] Branch unchanged: ${CURRENT_BRANCH_NAME}, checking PREVIOUS_COMMIT for incremental build"
38
+ if [ -n "${PREVIOUS_COMMIT}" ]; then
39
+ # 验证 commit 是否存在且有效
40
+ if git rev-parse --verify "${PREVIOUS_COMMIT}" >/dev/null 2>&1; then
41
+ # 关键检查:验证 PREVIOUS_COMMIT 是否是当前 HEAD 的祖先
42
+ # 这可以避免以下问题:
43
+ # 1. Rebase/Force push:PREVIOUS_COMMIT 不再是当前分支的祖先
44
+ # 2. Tag 被其他分支更新:PREVIOUS_COMMIT 不是当前分支的祖先
45
+ CURRENT_HEAD="$(git rev-parse HEAD)"
46
+ if git merge-base --is-ancestor "${PREVIOUS_COMMIT}" "${CURRENT_HEAD}" 2>/dev/null; then
47
+ # PREVIOUS_COMMIT 是当前 HEAD 的祖先,可以安全使用
48
+ BASE_REF="${PREVIOUS_COMMIT}"
49
+ echo "[before_build] Use PREVIOUS_COMMIT as BASE_REF: ${BASE_REF} (ancestor check passed)"
50
+ # 为 turbo --filter 准备语法形如 ...[<BASE_REF>]
51
+ TURBO_FILTER="...[${BASE_REF}]"
52
+ export TURBO_FILTER
53
+ echo "[before_build] TURBO_FILTER=${TURBO_FILTER} (incremental build)"
54
+ else
55
+ # PREVIOUS_COMMIT 不是当前 HEAD 的祖先,降级为全量构建
56
+ echo "[before_build] Warning: PREVIOUS_COMMIT=${PREVIOUS_COMMIT} is not an ancestor of HEAD=${CURRENT_HEAD}"
57
+ echo "[before_build] Possible reasons: rebase/force-push, tag updated by another branch, or shallow clone issue"
58
+ echo "[before_build] Falling back to full build (no filter)"
59
+ unset TURBO_FILTER
60
+ fi
61
+ else
62
+ echo "[before_build] Warning: PREVIOUS_COMMIT=${PREVIOUS_COMMIT} is not a valid commit, will perform full build"
63
+ unset TURBO_FILTER
64
+ fi
65
+ else
66
+ # PREVIOUS_COMMIT 未设置,进行全量构建
67
+ echo "[before_build] PREVIOUS_COMMIT not set, will perform full build (no filter)"
68
+ unset TURBO_FILTER
69
+ fi
70
+ fi
71
+ else
72
+ # LAST_SUCCESS_BRANCH 未设置,说明是第一次构建或 Jenkins 未配置该环境变量
73
+ echo "[before_build] LAST_SUCCESS_BRANCH not set, will perform full build (no filter)"
74
+ # 不设置 TURBO_FILTER,这样 package.json 中的 ${TURBO_FILTER:+--filter=${TURBO_FILTER}} 不会生效
75
+ unset TURBO_FILTER
76
+ fi
@@ -20,11 +20,24 @@ echo "项目版本: $VERSION"
20
20
  # 切换到项目根目录,确保后续命令在根目录下运行
21
21
  cd "$PROJECT_ROOT"
22
22
 
23
+ # 导出 PROJECT_ROOT 供 before_build.sh 使用
24
+ export PROJECT_ROOT
25
+
26
+ # 在执行构建前,计算 BASE_REF / TURBO_FILTER 等增量构建信息
27
+ if [ -f "$PROJECT_ROOT/CICD/before_build.sh" ]; then
28
+ # shellcheck disable=SC1090
29
+ source "$PROJECT_ROOT/CICD/before_build.sh"
30
+ fi
31
+
23
32
  # 设置子应用的 CDN 公共路径(开发环境)
24
33
  export CDN_PUBLIC_PATH="https://cdn-portal-dev.micoplatform.com/<%= projectName %>/${VERSION}/"
25
34
  echo "CDN_PUBLIC_PATH: $CDN_PUBLIC_PATH"
26
35
 
27
36
  pnpm run build:development
28
37
 
29
- echo "VERSION=$VERSION" > .env_x_<%= projectName %>
38
+ # 只有在 CI 环境时才写入版本号文件(覆盖写入)
39
+ if [ "${CI}" = "true" ]; then
40
+ echo "VERSION=$VERSION" > .env_x_portal-web
41
+ fi
42
+
30
43
 
@@ -20,11 +20,23 @@ echo "项目版本: $VERSION"
20
20
  # 切换到项目根目录,确保后续命令在根目录下运行
21
21
  cd "$PROJECT_ROOT"
22
22
 
23
+ # 导出 PROJECT_ROOT 供 before_build.sh 使用
24
+ export PROJECT_ROOT
25
+
26
+ # 在执行构建前,计算 BASE_REF / TURBO_FILTER 等增量构建信息(用于增量构建)
27
+ if [ -f "$PROJECT_ROOT/CICD/before_build.sh" ]; then
28
+ # shellcheck disable=SC1090
29
+ source "$PROJECT_ROOT/CICD/before_build.sh"
30
+ fi
31
+
23
32
  # 设置子应用的 CDN 公共路径(生产环境)
24
33
  export CDN_PUBLIC_PATH="https://cdn-portal.micoplatform.com/<%= projectName %>/${VERSION}/"
25
34
  echo "CDN_PUBLIC_PATH: $CDN_PUBLIC_PATH"
26
35
 
27
36
  pnpm run build:production
28
37
 
29
- echo "VERSION=$VERSION" > .env_x_<%= projectName %>
38
+ # 只有在 CI 环境时才写入版本号文件(覆盖写入)
39
+ if [ "${CI}" = "true" ]; then
40
+ echo "VERSION=$VERSION" > .env_x_portal-web
41
+ fi
30
42
 
@@ -20,11 +20,24 @@ echo "项目版本: $VERSION"
20
20
  # 切换到项目根目录,确保后续命令在根目录下运行
21
21
  cd "$PROJECT_ROOT"
22
22
 
23
+ # 导出 PROJECT_ROOT 供 before_build.sh 使用
24
+ export PROJECT_ROOT
25
+
26
+ # 在执行构建前,计算 BASE_REF / TURBO_FILTER 等增量构建信息
27
+ if [ -f "$PROJECT_ROOT/CICD/before_build.sh" ]; then
28
+ # shellcheck disable=SC1090
29
+ source "$PROJECT_ROOT/CICD/before_build.sh"
30
+ fi
31
+
32
+
23
33
  # 设置子应用的 CDN 公共路径(测试环境)
24
34
  export CDN_PUBLIC_PATH="https://cdn-portal-test.micoplatform.com/<%= projectName %>/${VERSION}/"
25
35
  echo "CDN_PUBLIC_PATH: $CDN_PUBLIC_PATH"
26
36
 
27
37
  pnpm run build:testing
28
38
 
29
- echo "VERSION=$VERSION" > .env_x_<%= projectName %>
39
+ # 只有在 CI 环境时才写入版本号文件(覆盖写入)
40
+ if [ "${CI}" = "true" ]; then
41
+ echo "VERSION=$VERSION" > .env_x_portal-web
42
+ fi
30
43
 
@@ -28,14 +28,14 @@ const config: ReturnType<typeof defineConfig> = {
28
28
  proxy: {
29
29
  '/api': {
30
30
  // 要代理的地址
31
- target: 'https://dashboard-api-test.micoplatform.comn',
31
+ target: 'https://dashboard-api-test.micoplatform.com',
32
32
  // 配置了这个可以从 http 代理到 https
33
33
  // 依赖 origin 的功能可能需要这个,比如 cookie
34
34
  changeOrigin: true,
35
35
  },
36
36
  '/proxy/audit_svr': {
37
37
  // 要代理的地址
38
- target: 'https://dashboard-api-test.micoplatform.comn',
38
+ target: 'https://dashboard-api-test.micoplatform.com',
39
39
  // 配置了这个可以从 http 代理到 https
40
40
  // 依赖 origin 的功能可能需要这个,比如 cookie
41
41
  changeOrigin: true,
@@ -20,4 +20,9 @@ export default [
20
20
  component: './403',
21
21
  name: '无权限',
22
22
  },
23
+ {
24
+ path: '/*',
25
+ component: './404',
26
+ name: '页面不存在',
27
+ },
23
28
  ];
@@ -0,0 +1,103 @@
1
+ # 404 页面
2
+
3
+ > 创建时间:2025-01-27
4
+
5
+ ## 功能概述
6
+
7
+ 当用户访问不存在的路由时,展示 404 页面并提供导航选项,支持返回上页或跳转至第一个有权限访问的路由。
8
+
9
+ ## 技术方案
10
+
11
+ ### 技术栈
12
+
13
+ - 框架:React 18 + @umijs/max
14
+ - UI 组件:Arco Design `Result`、`Button`、`Space`
15
+ - 路由:React Router 6 通配符路由
16
+
17
+ ### 核心实现
18
+
19
+ 1. 使用 Umi 路由通配符 `/*` 捕获所有未匹配的路径
20
+ 2. 复用 403 页面的布局风格,保持 UI 一致性
21
+ 3. 动态计算第一个可访问路由:从菜单数据中提取路由,根据用户权限过滤后返回首个有效路径
22
+
23
+ ## 文件清单
24
+
25
+ ### 新增文件
26
+
27
+ | 文件路径 | 说明 |
28
+ | --- | --- |
29
+ | `src/pages/404/index.tsx` | 404 页面组件 |
30
+
31
+ ### 修改文件
32
+
33
+ | 文件路径 | 修改内容 |
34
+ | --- | --- |
35
+ | `config/routes.ts` | 添加通配符路由 `/*` |
36
+
37
+ ## API / 组件接口
38
+
39
+ ### NotFoundPage
40
+
41
+ 无外部 Props,使用 Umi 全局状态获取用户信息。
42
+
43
+ ### getFirstAvailablePath
44
+
45
+ ```typescript
46
+ /**
47
+ * 获取第一个可访问的路由路径
48
+ */
49
+ const getFirstAvailablePath = (filterOptions: MenuFilterOptions): string;
50
+ ```
51
+
52
+ **逻辑说明**:
53
+
54
+ 1. 从 `window.__MICO_MENUS__` 获取菜单数据
55
+ 2. 根据 `disableAuth` 配置决定是否过滤权限
56
+ 3. 调用 `filterMenuItems` 过滤无权限菜单
57
+ 4. 调用 `extractRoutes` 提取路由列表
58
+ 5. 返回第一个路由的 `path`,若无则返回 `/`
59
+
60
+ ## 路由配置
61
+
62
+ ```typescript
63
+ // config/routes.ts
64
+ {
65
+ path: '/*',
66
+ component: './404',
67
+ name: '页面不存在',
68
+ }
69
+ ```
70
+
71
+ 通配符路由放在路由配置末尾,匹配所有未被其他路由匹配的路径。
72
+
73
+ ## 使用示例
74
+
75
+ 用户访问 `/non-existent-page` 时:
76
+
77
+ 1. 路由系统无法匹配到具体路由
78
+ 2. 通配符路由 `/*` 生效
79
+ 3. 渲染 404 页面,显示两个按钮:
80
+ - **返回上页**:调用 `history.back()`
81
+ - **前往首页**:跳转至第一个有权限的路由
82
+
83
+ ## 设计决策
84
+
85
+ | 决策点 | 选择 | 理由 |
86
+ | --- | --- | --- |
87
+ | UI 组件 | Arco Design Result | 与 403 页面保持一致,复用现有组件库 |
88
+ | 首页跳转逻辑 | 动态获取第一个可访问路由 | 适应动态菜单配置,不硬编码路径 |
89
+ | 权限过滤 | 复用 filterMenuItems | 与菜单权限逻辑保持一致 |
90
+
91
+ ## 相关文件
92
+
93
+ | 文件 | 说明 |
94
+ | --- | --- |
95
+ | `src/pages/403/index.tsx` | 403 页面,UI 风格参考 |
96
+ | `src/common/menu/parser.ts` | 菜单解析工具函数 |
97
+ | `src/constants/index.ts` | `isAuthDisabled` 权限控制函数 |
98
+
99
+ ## 注意事项
100
+
101
+ - 通配符路由必须放在路由配置最后,否则会提前匹配
102
+ - 动态路由(从 `window.__MICO_MENUS__` 注入)的 404 场景由 `layouts/index.tsx` 处理
103
+ - 此 404 页面主要处理静态路由未匹配的情况
@@ -1,7 +1,6 @@
1
1
  # 菜单权限控制
2
2
 
3
- > 创建时间:2026-01-24
4
- > 更新时间:2026-01-26
3
+ > 创建时间:2026-01-24 更新时间:2026-01-27
5
4
 
6
5
  ## 功能概述
7
6
 
@@ -13,10 +12,10 @@
13
12
 
14
13
  ### 认证 vs 授权
15
14
 
16
- | 概念 | 英文 | 作用 | 配置项 |
17
- | --- | --- | --- | --- |
18
- | 认证 | Authentication | 确认用户身份(是否登录) | `noAuthRouteList` |
19
- | 授权 | Authorization | 确认用户权限(能否访问) | `noPermissionRouteList` |
15
+ | 概念 | 英文 | 作用 | 配置项 |
16
+ | ---- | -------------- | ------------------------ | ----------------------- |
17
+ | 认证 | Authentication | 确认用户身份(是否登录) | `noAuthRouteList` |
18
+ | 授权 | Authorization | 确认用户权限(能否访问) | `noPermissionRouteList` |
20
19
 
21
20
  ### 四种路由场景
22
21
 
@@ -103,8 +102,8 @@
103
102
 
104
103
  ### 新增文件
105
104
 
106
- | 文件路径 | 说明 |
107
- | --- | --- |
105
+ | 文件路径 | 说明 |
106
+ | ------------------------- | ------------------ |
108
107
  | `src/pages/403/index.tsx` | 403 无权限页面组件 |
109
108
 
110
109
  ### 修改文件
@@ -204,13 +203,13 @@ window.__MICO_CONFIG__ = {
204
203
  noAuthRouteList: [
205
204
  '/',
206
205
  '/subapp',
207
- '/public/*', // 前缀匹配
206
+ '/public/*', // 前缀匹配
208
207
  ],
209
208
  // 免权限校验路由(跳过菜单权限检查)
210
209
  noPermissionRouteList: [
211
210
  '/',
212
211
  '/subapp',
213
- '/settings', // 登录后的公共页面
212
+ '/settings', // 登录后的公共页面
214
213
  ],
215
214
  disableAuth: false,
216
215
  };
@@ -230,10 +229,7 @@ export const NO_AUTH_ROUTE_LIST: string[] = [
230
229
  ];
231
230
 
232
231
  // 静态免权限校验路由(始终生效)
233
- export const NO_PERMISSION_ROUTE_LIST: string[] = [
234
- '/403',
235
- '/404',
236
- ];
232
+ export const NO_PERMISSION_ROUTE_LIST: string[] = ['/403', '/404'];
237
233
  ```
238
234
 
239
235
  ### 菜单过滤结果
@@ -291,6 +287,56 @@ if (!isAuthReady) {
291
287
  | 超级用户 | 跳过所有检查 | 管理员需要完整访问权限 |
292
288
  | 免权限路由的菜单 | 显示全部 | 用户访问公开页面时应能看到所有导航选项 |
293
289
  | 免权限路由的子应用 | 直接加载 | 不等待 currentUser,避免加载卡住 |
290
+ | 静态路由不受权限控制 | 默认允许访问 | 见下方"静态路由与动态路由"说明 |
291
+
292
+ ## 静态路由与动态路由
293
+
294
+ ### 定义
295
+
296
+ | 类型 | 来源 | 示例 |
297
+ | --- | --- | --- |
298
+ | **静态路由** | 代码中定义 (`config/routes.ts`) | `/`, `/403`, `/404`, `/user/login` |
299
+ | **动态路由** | 后端菜单配置 (`window.__MICO_MENUS__`) | `/queue-management`, `/quality-check` |
300
+
301
+ ### 权限控制范围
302
+
303
+ **当前设计:权限控制仅作用于动态路由,静态路由默认允许访问。**
304
+
305
+ ```
306
+ 权限判断逻辑(isForbidden):
307
+ 1. 检查 isAuthDisabled() → 关闭则全部允许
308
+ 2. 检查 isNoPermissionRoute() → 在免权限列表中则允许
309
+ 3. 检查 currentRoute(有权限路由) → 找到则允许
310
+ 4. 检查 routeInAll(所有动态路由) → 存在则返回 403
311
+ 5. 都不匹配 → 交给 Umi 处理(静态路由走这里)
312
+ ```
313
+
314
+ ### 设计理由
315
+
316
+ 1. **职责分离**:静态路由是框架层面的基础设施(登录、错误页),动态路由才是业务功能
317
+ 2. **简化配置**:不需要额外配置哪些静态路由需要权限,减少出错概率
318
+ 3. **向后兼容**:现有部署无需任何改动
319
+ 4. **复杂度控制**:避免引入更多配置项增加理解成本
320
+
321
+ ### 影响
322
+
323
+ 当用户 `is_superuser=false` 且 `side_menus=[]` 时:
324
+
325
+ | 路由 | 结果 | 原因 |
326
+ | --- | --- | --- |
327
+ | `/` (Home) | ✅ 正常显示 | 静态路由,不受权限控制 |
328
+ | `/403` | ✅ 正常显示 | 在 `noPermissionRouteList` 中 |
329
+ | `/404` | ✅ 正常显示 | 在 `noPermissionRouteList` 中 |
330
+ | `/user/login` | ✅ 正常显示 | 静态路由 + 在 `noAuthRouteList` 中 |
331
+ | `/queue-management` | ❌ 显示 403 | 动态路由,无权限 |
332
+
333
+ ### 如需控制静态路由
334
+
335
+ 如果业务上需要让某个静态路由(如 `/`)也受权限控制,有以下方案:
336
+
337
+ 1. **方案 A**:将该路由从静态路由改为动态路由(通过菜单配置)
338
+ 2. **方案 B**:在对应页面组件内部自行判断权限并重定向
339
+ 3. **方案 C**:扩展 `isForbidden` 逻辑(需额外开发,当前未实现)
294
340
 
295
341
  ## 注意事项
296
342
 
@@ -298,7 +298,7 @@ if (typeof window !== 'undefined') {
298
298
  return;
299
299
  }
300
300
 
301
- log('用户交互开始:', event.type);
301
+ // log('用户交互开始:', event.type);
302
302
  isInUserInteraction = true;
303
303
  // 记录交互开始时间,用于判断意图是否在当前交互期间设置的
304
304
  currentInteractionStartTime = Date.now();
@@ -308,7 +308,7 @@ if (typeof window !== 'undefined') {
308
308
  setTimeout(() => {
309
309
  isInUserInteraction = false;
310
310
  interactionEndTime = Date.now();
311
- log('用户交互结束');
311
+ // log('用户交互结束');
312
312
  }, 0);
313
313
  }
314
314
  };
@@ -0,0 +1,82 @@
1
+ import {
2
+ extractRoutes,
3
+ filterMenuItems,
4
+ getWindowMenus,
5
+ type MenuFilterOptions,
6
+ } from '@/common/menu';
7
+ import { isAuthDisabled } from '@/constants';
8
+ import { Button, Result, Space } from '@arco-design/web-react';
9
+ import { history, useModel } from '@umijs/max';
10
+ import React, { useMemo } from 'react';
11
+
12
+ /**
13
+ * 获取第一个可访问的路由路径
14
+ */
15
+ const getFirstAvailablePath = (filterOptions: MenuFilterOptions): string => {
16
+ const menus = getWindowMenus();
17
+
18
+ // 根据权限过滤菜单
19
+ const filteredMenus = isAuthDisabled()
20
+ ? menus
21
+ : filterMenuItems(menus, filterOptions);
22
+
23
+ // 提取路由
24
+ const routes = extractRoutes(filteredMenus);
25
+
26
+ // 返回第一个有效路由,默认返回首页
27
+ return routes[0]?.path || '/';
28
+ };
29
+
30
+ const NotFoundPage: React.FC = () => {
31
+ const { initialState } = useModel('@@initialState');
32
+ const currentUser = initialState?.currentUser;
33
+
34
+ const filterOptions = useMemo<MenuFilterOptions>(
35
+ () => ({
36
+ isSuperuser: currentUser?.is_superuser,
37
+ sideMenus: (currentUser?.side_menus || []) as string[],
38
+ }),
39
+ [currentUser?.is_superuser, currentUser?.side_menus],
40
+ );
41
+
42
+ const firstAvailablePath = useMemo(
43
+ () => getFirstAvailablePath(filterOptions),
44
+ [filterOptions],
45
+ );
46
+
47
+ const handleGoBack = () => {
48
+ history.back();
49
+ };
50
+
51
+ const handleGoFirst = () => {
52
+ history.push(firstAvailablePath);
53
+ };
54
+
55
+ return (
56
+ <div
57
+ style={{
58
+ display: 'flex',
59
+ justifyContent: 'center',
60
+ alignItems: 'center',
61
+ height: '100%',
62
+ minHeight: 400,
63
+ }}
64
+ >
65
+ <Result
66
+ status="404"
67
+ title="页面不存在"
68
+ subTitle="抱歉,您访问的页面不存在"
69
+ extra={
70
+ <Space>
71
+ <Button onClick={handleGoBack}>返回上页</Button>
72
+ <Button type="primary" onClick={handleGoFirst}>
73
+ 前往首页
74
+ </Button>
75
+ </Space>
76
+ }
77
+ />
78
+ </div>
79
+ );
80
+ };
81
+
82
+ export default NotFoundPage;
@@ -12,9 +12,9 @@
12
12
  "scripts": {
13
13
  "dev": "node scripts/dev.js",
14
14
  "build": "dotenv -e .env -e .env.local -e .env.production -e .env.production.local -- turbo run build && node scripts/collect-dist.js",
15
- "build:development": "dotenv -e .env -e .env.local -e .env.development -e .env.development.local -- turbo run build:development && node scripts/collect-dist.js",
16
- "build:testing": "dotenv -e .env -e .env.local -e .env.testing -e .env.testing.local -- turbo run build:testing && node scripts/collect-dist.js",
17
- "build:production": "dotenv -e .env -e .env.local -e .env.production -e .env.production.local -- turbo run build:production && node scripts/collect-dist.js",
15
+ "build:development": "dotenv -e .env -e .env.local -e .env.development -e .env.development.local -- turbo run build:development ${TURBO_FILTER:+--filter=${TURBO_FILTER}} && node scripts/collect-dist.js",
16
+ "build:testing": "dotenv -e .env -e .env.local -e .env.testing -e .env.testing.local -- turbo run build:testing ${TURBO_FILTER:+--filter=${TURBO_FILTER}} && node scripts/collect-dist.js",
17
+ "build:production": "dotenv -e .env -e .env.local -e .env.production -e .env.production.local -- turbo run build:production ${TURBO_FILTER:+--filter=${TURBO_FILTER}} && node scripts/collect-dist.js",
18
18
  "build:local": "dotenv -e .env -e .env.local -- turbo run build:local && node scripts/collect-dist.js",
19
19
  "lint": "eslint . --ext .js,.jsx,.ts,.tsx && turbo run lint",
20
20
  "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix && turbo run lint:fix",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generator-mico-cli",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Yeoman generator for Mico CLI projects",
5
5
  "keywords": [
6
6
  "yeoman-generator",