# README

## 命令说明：

安装：

```
yarn  install
```

快速启动：

```
yarn start
```

## 一、功能概述：

### 1.1、目录结构说明：

#### .env

环境变量，比如：

```json
PORT=8888
COMPRESS=none
```

#### mock

存放 mock 文件，此目录下所有 `.ts` / `.js` 文件会被 mock 服务加载，从而提供模拟数据，使用方法详见 [Mock](https://umijs.org/docs/guides/mock) 。

#### dist 目录

执行 `umi build` 后产物的默认输出文件夹。可通过 [`outputPath`](https://umijs.org/docs/api/config#outputpath) 配置修改产物输出文件夹。

#### public 目录

存放固定的静态资源，如存放 `public/image.png` ，则开发时可以通过 `/image.png` 访问到，构建后会被拷贝到输出文件夹。

#### config 目录

##### config.ts

配置文件，集中管理所有的配置；包含 Umi 所有[非运行时配置](https://umijs.org/docs/api/config)（运行时配置一般定义于 [`app.ts`](https://umijs.org/docs/guides/directory-structure#apptstsx)）。

若你需要在不同环境中加载不同配置，这在 Umi 中是根据 [`UMI_ENV`](https://umijs.org/docs/guides/env-variables#umi_env) 来实现的，一个不同环境启动的例子：

```json
{   
"scripts": { 
	"dev": "umi dev",  
	"dev:pre": "cross-env UMI_ENV=pre umi dev"   
	}
 }
```

##### defaultSettings.ts

layout 配置文件，包含整体的布局与风格；

##### pyoxy.ts

代理配置文件夹，不同环境的代理；

##### requestErrorConfig.ts

同一请求拦截、封装、埋点、处理、同一请求头配置；

##### routes.ts /childRouter.ts

路由配置文件，格式为路由信息的数组。 主系统配置在routes.ts, 子系统在childRouter.ts中配置。

更多内容详见[https://umijs.org/docs/guides/routes](https://umijs.org/docs/guides/routes)

##### theme.config.json

全局样式组件， 由主题编辑器生成，用于全局样式的调整，覆盖；

#### src目录

##### app.tsx

[运行时配置](https://umijs.org/docs/api/runtime-config) 文件，可以在这里扩展运行时的能力，比如修改路由、修改 render 方法等。

运行时配置带来的逻辑会在浏览器中运行，因此当有远程配置、动态内容时，这些我们在本地开发时还不确定，不能写死，所以需要在浏览器实际运行项目时动态获取他们。

##### assets

静态资源放置在此，例如pages文件夹下组件所用的图片、字体；

##### components 公用组件文件夹

页面中多次复用的组件放置在改文件中

详见index.md说明文件中

##### pages 目录

所有页面、及页面相关组件放置这里

约定式路由默认以 `pages/*` 文件夹的文件层级结构来生成路由表。

在配置式路由中，`component` 若写为相对路径，将从该文件夹为起点开始寻找文件；

##### locales目录

多语言配置目录，不同的语言分不同的文件夹存储， 每个模块一个文件 方便查找 修改；

在en-US.ts中需要进行统一导入及导出；

例：

```typescript
import columns from './en-US/columns';
import component from './en-US/component';
import dictionaries from './en-US/dictionaries';
import forms from './en-US/forms';
import globalHeader from './en-US/globalHeader';
import pages from './en-US/layoutPages';
import loginLog from './en-US/loginLog';
import menu from './en-US/menu';
import operationLog from './en-US/operationLog';
import pwa from './en-US/pageMenuManagement';
import parameterManagement from './en-US/parameterManagement';
import role from './en-US/roleManagement';
import settings from './en-US/settings';
import userCenter from './en-US/userCenter';


export default {
  'navBar.lang': 'Languages',
  
  'layout.logout': 'Logout',
  'layout.user.link.help': 'Help',
  'layout.user.link.privacy': 'Privacy',
  'layout.user.link.terms': 'Terms',
  'app.title': 'APP Title',
  ...globalHeader,
  ...menu,
  ...settings,
  ...pwa,
  ...component,
  ...pages,
  ...columns,
  ...forms,
  ...loginLog,
  ...operationLog,
  ...parameterManagement,
  ...userCenter,
  ...role,
  ...dictionaries,

};
```

##### models

所谓的 Model，就是一个自定义的 `hooks`，没有任何使用者需要关注的“黑魔法”。

当我们需要获取 Model 中的全局数据时，调用该命名空间即可。例如，对于 Model 文件 `userModel.ts`，它的命名空间为 `userModel`。

编写一个默认导出的函数：

```js
// src/models/userModel.ts
export default function Page() {
  constuser = {username:'umi',  };
  return { user };
};
```

这就是一个 Model。插件所做的工作就是将其中的状态或数据变成了 **全局数据** ，不同的组件在使用该 Model 时，拿到的是同一份状态或数据。

💡Model 文件需要默认导出一个函数，此函数定义了一个 `hook`。对于不符合此规范的文件，将会被过滤掉，并无法通过命名空间调用。

##### utils

常用工具类函数封装，全局常量、正则、时间格式处理、常用方法封装等...

#### access

我们约定了 `src/access.ts` 为我们的权限定义文件，该文件需要默认导出一个方法，导出的方法会在项目初始化时被执行。该方法需要返回一个对象，对象的每一个值就对应定义了一条权限。如下所示：

```typescript
// src/access.ts
export default function (initialState) {
  const { userId, role } = initialState;
 
  return {
    canReadFoo: true,
    canUpdateFoo: role === 'admin',
    canDeleteFoo: (foo) => {
      return foo.ownerId === userId;
    },
  };
}
```

其中 `initialState` 是通过初始化状态插件 `initial-state` 提供的数据，你可以使用该数据来初始化你的用户权限。

配合 [layout](https://umijs.org/docs/max/layout-menu) 插件你可以很简单的实现针对某些页面的权限控制。如下所示，只有拥有了 canReadPageA （在 `src/access.ts` 中定义）权限，用户才可以访问该页面。否则会默认渲染 Layout 插件内置的权限错误页面。

#### global.less/[`overrides.less`](https://umijs.org/docs/guides/directory-structure#overridescsslesssassscss)

全局样式文件。

当你有需要全局使用的样式时，请考虑加入此文件。

💡需要注意的是，此文件的优先级在第三方组件库的样式之后，所以当你有覆盖第三方库样式的需求时，请使用 [`overrides.less`](https://umijs.org/docs/guides/directory-structure#overridescsslesssassscss) 。

#### loading.tsx

全局加载组件。

Umi 4 默认 [按页分包](https://umijs.org/blog/code-splitting) ，从而在页面切换时存在加载过程，通过该文件来配置加载动画。

### 1.2、微前端架构：

父应用里，我们通过导航栏切换路由后，下方显示的内容来自于不同的子应用。子应用支持单独打开；子应用之间也支持任意的嵌套。

[关于 Qiankun 微前端的更多介绍请参阅此文档](https://umijs.org/docs/max/micro-frontend#microappprops)

#### 1.2.1、qiankun框架挂载配置，主系统挂载配置：config/config.ts中代码如下：

##### 1.2.1.1  父子系统在不同的服务器运行

```typescript
...
qiankun: {
    master: {
      apps: [
        {
          name: 'dashboard',
	  //是否在开发环境？ 开发环境端口号 ： 部署环境url
          entry: isDev?'//localhost:3015': microAppUrl,
          activeRule: '/dashboard',
          history:'base',
        }
      ],
    },
  },
```

##### 1.2.1.2  父子系统在同一个服务器，同端口运行

```typescript
...
qiankun: {
    master: {
      apps: [
        {
          name: 'dashboard',
	  //是否在开发环境？ 开发环境端口号 ： 部署环境下相对的路径
          entry: isDev?'//localhost:3015':'/child/dashboard/',
          activeRule: '/dashboard',
          history:'base',
        }
      ],
    },
  },
```

#### 1.2.2、父系统router 挂载方式

##### 1.2.2.1 使用路由挂载；

```typescript

 {
      path: '/large-screen-manage',//大屏多维数据管理
      name: 'dashboard.management',
      icon: 'AppstoreOutlined',
      routes: [
        {
          path: '/large-screen-manage/*',
          microApp: 'dashboard',
	  microAppProps: {
		...
	  }
        }
        ]
    },
```

##### 1.2.2.2 使用组件方式挂载

```
 {
      path: '/dashboard',
      name: 'dashboard',
      routes: [
        {
  
          path: '/dashboard/*',
          access: 'dashboard',
          component: './qiankun/Dashboard',
        },
      ]  
    },
```

qiankun/Dashboard.tsx 代码如下：

```typescript
import React, { useState } from 'react';
import { MicroApp, useAccess} from '@umijs/max';
import { CURRENT_MENU, TOKEN } from '@/utils/constant';

const Dashboard: React.FC = () => {
  const access = useAccess();
  const [globalState] = useState<any>({
    token: localStorage.getItem(TOKEN),
    menuTree: localStorage.getItem(CURRENT_MENU),
    access,
  });

  return (<MicroApp 
    name="dashboard"
    base="/dashboard"
    autoSetLoading
    globalState={globalState}
    autoCaptureError 
    />);
};
export default Dashboard;
```

##### 1.2.2.3 microAppProps 属性如下

| 属性                 | 必填 | 说明                                                                                   | 类型                                | 默认值        |
| -------------------- | ---- | -------------------------------------------------------------------------------------- | ----------------------------------- | ------------- |
| `autoSetLoading`   | 否   | 自动设置微应用的加载状态                                                               | `boolean`                         | `false`     |
| `loader`           | 否   | 自定义的微应用加载状态组件                                                             | `(loading) => React.ReactNode`    | `undefined` |
| `autoCaptureError` | 否   | 自动设置微应用的错误捕获                                                               | `boolean`                         | `false`     |
| `errorBoundary`    | 否   | 自定义的微应用错误捕获组件                                                             | `(error: any) => React.ReactNode` | `undefined` |
| `className`        | 否   | 微应用的样式类                                                                         | `string`                          | `undefined` |
| `wrapperClassName` | 否   | 包裹微应用加载组件、错误捕获组件和微应用的样式类，仅在启用加载组件或错误捕获组件时有效 | `string`                          | `undefine`  |
