ant desgn react
一、基础使用
1. 文件夹结构介绍
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | ├── config                   # umi 配置,包含路由,构建等配置├── mock                     # 本地模拟数据
 ├── public
 │   └── favicon.png          # Favicon
 ├── src
 │   ├── assets               # 本地静态资源
 │   ├── e2e                  # 集成测试用例
 │   ├── layouts              # 通用布局
 │   ├── models               # 全局 dva model
 │   ├── pages                # 业务页面入口
 │   ├── services             # 后台接口服务
 │   ├── shared/etc_bfplus                # 公共组件及工具库
 │   ├── locales              # 国际化资源
 │   ├── global.less          # 全局样式
 │   └── global.tsx            # 全局页面
 ├── tests                    # 测试工具
 ├── README.md
 └── package.json
 
 | 
2. 项目启动
在 terminal 执行命令(默认开启 mock)
本地访问地址为http://localhost:8005/user/login
如不需要 mock,执行命令
本地启动的端口默认是 8005,如果需要修改的话,更改.env 文件
3. 本地调试(proxy 的反向代理)
- 打开 config/config.ts,对应修改不同的接口服务所代理的服务器域名,如修改‘/api’前缀的接口服务为自己本地 IP,直接修改 target 的值

4. 页面代码结构推荐(请遵循此守则开发)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | src├── components
 └── pages
 ├── Welcome
 |   ├── components
 |   ├── index.tsx
 |   └── index.less
 ├── Order
 |   ├── index.tsx
 |   └── index.less
 ├── user
 |   ├── components
 |   ├── Login
 |   ├── Register
 |   └── util.ts
 └── *
 
 | 
二、页面开发
1. 快速创建 CRUD 页面
- 创建路由组件
- 要生成模块,模块下包含多个路由组件,在 terminal 执行命令 npm run temp 目录(强烈要求这种方式)
 
| 12
 
 | eg:npm run temp test/Table
 
 | 
会在 src/pages 目录下创建 test 文件夹,内包含 Table 文件夹,文件夹里面包含 index.tsx 和 d.ts 两个文件。
b. 要生成单路由组件,在 terminal 执行命令 npm run temp 组件名
会在 src/pages 目录下创建 Order 文件夹,内包含 index.tsx 以及 d.ts 两个文件,d.ts 文件是该模块的 typescript 描述文件,用来指定对象的类型。
- 将文件加入菜单和路由
a. 在 config/routes 文件夹内创建一个有关该模块的所有路由文件,命名规则是模块名.routes.ts,比如售后模块,after-sale.routes.ts,像上面我们新增的 test 模块,我们就创建一个 test.routes.ts 文件。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | export default {
 path: "/test",
 component: "../layouts/BasicLayout",
 routes: [
 
 {
 path: "/test/table",
 name: "表格",
 component: "./test/Table/index",
 },
 ],
 };
 
 | 
b. 创建完路由文件之后,要在 config/routes.js 文件中引入


| 12
 
 | import testRoutes from "./routes/test.routes";
 
 | 
- 定义接口请求文件
 在 services 文件夹创建一个该模块的接口请求文件,如 test.ts,用于该模块的所有请求。
| 12
 3
 4
 5
 6
 7
 
 | import request from "@bfp/utils/request";
 import downloadData from "@bfp/utils/downLoad";
 
 
 export const apiTestGetList = async (data: any): Promise<any> =>
 request("/api/template/getList", { data, method: "POST" });
 
 | 
创建完 test.ts 之后,在 services/index.ts 文件中引入该模块接口文件
- 打开浏览器(已登录状态),访问 http://localhost:8005/test/table,可以看到已经能成功访问该页面了

2. 介绍 CRUD 页面中的自定义组件 Grid 用法
| 1
 | <Grid />组件由自定义组件<SearchForm />和<TableComponent />两部分组成
 | 

该组件暴露两个实例,一个是表单的实例 form,一个是表格的实例 tableCom,当需要操作该表单或者表格的一些方法,可通过这两个实例操作!
| 1
 | eg: const form = $table.current._form 
 | 
当定义columns的时候,设置query属性,Grid 会根据query的定义自动生成表单,query 对应的 type 配置:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | type QueryType = {
 
 label?: string;
 
 
 
 name: string;
 
 
 type: "select" | "datePicker";
 
 
 render: () => React.ReactNode;
 
 
 colProps: ColProps;
 
 
 formItemProps: FormItemProps;
 
 
 selectConfig?: {
 
 label?: string;
 
 
 value?: string;
 
 
 options?:
 | Promise<object | { key: string; value: string | number }[]>
 | object
 | { key: string; value: string | number }[];
 
 
 showAll?: Boolean;
 } & SelectProps<string | number>;
 
 
 pickerConfig?: RangePickerProps;
 
 elementProps?: any;
 };
 
 | 
页面都自动生成默认示例了,可根据需求自行调整:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 
 | const columns = [{
 title: "常规字段",
 dataIndex: "field1",
 },
 {
 title: "文本框查询",
 dataIndex: "field2",
 query: true,
 },
 {
 title: "下拉框查询",
 dataIndex: "field3",
 query: {
 type: "select",
 selectConfig: {
 options: testOptions,
 showAll: true,
 },
 },
 },
 {
 title: "日期期间查询",
 dataIndex: "field4",
 query: {
 type: "datePicker",
 name: "startField4-endField4",
 },
 },
 {
 title: "表单有表格隐藏",
 dataIndex: "field5",
 hideInTable: true,
 query: true,
 },
 {
 title: "操作",
 dataIndex: "opt",
 fixed: "right",
 render: () => (
 <Space>
 <Button type="primary">编辑</Button>
 <Button type="primary" danger onClick={() => onDelete()}>
 删除
 </Button>
 </Space>
 ),
 },
 ];
 
 | 
该组件同时暴露了两个操作表格的函数,一个是查询表格 handleTableChange(),一个是导出表格 handleExportTable(),当执行了新增或者编辑之后需要重刷新表格时,可执行如图代码:

| 1
 | $table.current.handleTableChange();
 | 
三、数据及状态管理
1. 常用 hooks
| 12
 3
 
 | eg:
 const [modalVisible, setModalVisible] = useState(false);
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | eg: useEffect(() => {
 async function fetchData() {
 const { data } = await getIncomeTypesEnums();
 setEnums(data);
 }
 
 fetchData();
 }, []);
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | export const GridContext = React.createContext();
 export default () => {
 <GridContext.Provider value={enums}>
 <Grid
 ref={childRef}
 renderForm={onSearchForm}
 columns={columns}
 getDataApi={getTypeManageList}
 >
 <div style={{ marginBottom: 20 }}>
 <Button
 type="primary"
 onClick={() => {
 setAddVisible(true), setCurrentDetail({});
 }}
 >
 添加
 </Button>
 </div>
 </Grid>
 </GridContext.Provider>;
 };
 
 
 import { GridContext } from "../index";
 
 const { cardCategoryEnumMap } = useContext(GridContext);
 
 | 
2. 简易数据流交互
中后台场景下,绝大多数页面的数据流转都是在当前页完成,在页面挂载的时候请求后端接口获取并消费,这种场景下并不需要复杂的数据流方案。但是也存在需要全局共享的数据,如用户的角色权限信息或者其他一些页面间共享的数据。为了实现在多个页面中的数据共享,以及一些业务可能需要的简易的数据流管理的场景,我们基于 hooks & umi 插件实现了一种轻量级的全局数据共享的方案。
a. 如何使用
在 src/models 目录下新建文件,文件名会成为 model 的 namespace。
| 1
 | eg. demo.ts 的 namespace 是 demo
 | 
一个 model 的内容需要是一个标准的 JavaScript function,并被默认导出,可以在 function 中使用 hooks.
例如下面的例子就是一个合法的 model:
| 12
 
 | export default () => "Hello World";
 
 | 
在实际使用场景中,model 可以包含其他 hooks,例如下面的计数器的例子:
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | import { useState, useCallback } from "react";
 
 export default () => {
 const [counter, setCounter] = useState(0);
 const increment = useCallback(() => setCounter((c) => c + 1), []);
 const decrement = useCallback(() => setCounter((c) => c - 1), []);
 return { counter, increment, decrement };
 };
 
 | 
b. 使用 model
在代码中使用 model,需要从 umi 中导出 useModel。useModel 是一个 React Custom Hook,传入 namespace 即可获取对应 model 的返回值。
| 12
 3
 4
 5
 6
 
 | import { useModel } from "umi";
 export default () => {
 const message = useModel("demo");
 return <div>{message}</div>;
 };
 
 | 
上述例子中的 message 会包含 demo model 的返回值,即:Hello World;
3. 如何进行 mock 数据调试
在 mock 文件夹下新建一个关于该模块的 mock 请求文件,如 user.ts,如果执行启动命令 npm run start 默认开启 mock 接口优先,如果 mock 文件夹下有定义改接口请求,则走这里定义的返回数据,如果没有定义则请求真实的 service 请求。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | 'POST /api/template/getList': (req: Request, res: Response) => {
 res.status(200).send({
 code: 0,
 data: {
 current: 1,
 orders: [],
 pages: 0,
 records: [
 {
 field1: 't1',
 field2: 't2',
 field3: 't3',
 field4: '2020-02-11',
 field5: 't5'
 },
 ],
 searchCount: true,
 size: 10,
 total: 0
 },
 msg: '成功操作'
 });
 },
 
 |