AntDesignPro单个页⾯⽬录结构以及⼀些常见的报错⼀、Ant Design Pro新增单个页⾯⽬录
1、 client -> src -> pages 中新增⽂件夹,⽐如 category的list
├── category
  └── list
   └── _mock.js  //  模拟数据(可忽略)
   └── model.js  //  处理请求的model组件,如果简单请求,直接写到 index.jsx中,简单化。(可忽略)
   └── index.jsx  //  主要的核⼼⽂件
  └── service.js  // 接⼝请求合集
  └── style.less  // category 公共样式
2、在 client ->  config -> conifig.js 中配置的routes 或者 route.js 中添加路由
{
path: '/category',
name: '分类',
icon: 'category',
routes: [
{
 path: '/category/list',
name: '分类列表列表',
component: './category/list'
}
]
},
index.jsx
import React, { Component } from 'react';
import { PageContainer } from '@ant-design/pro-layout';  // 引⼊布局组件
import { Card, Table, Select, Form, DatePicker, Button, Pagination } from 'antd';  // 引⼊ant design ui组件
import { getCategoryList } from '../service'; // 引⼊请求接⼝
import moment from 'moment';  // 时间⽇期组件,时间格式
import styles from '../style.less';  // 引⼊公共样式,styles.class
const { Option } = Select;  // 下拉框引⼊ Option
const { RangePicker } = DatePicker;  // 时间⽇期组件引⼊ RangePicker
const dateFormat = 'YYYY-MM-DD';  // 时间⽇期格式
// 筛选项变量
const selectData = [
{
label: '所属渠道',
name: 'channel',
style: {
width: '100px'
},
options: [
{
value: 'website',
name: '站内',
},
{
value: 'email',
name: '邮件',
}
]
},
];
// 创建类组件实例
class categoryList extends Component {
// 获取 DOM 元素节点,通过设置 ref,这⾥是表单form的ref
formRef = ateRef();
constructor(props) {
super(props);
this.state = {
channel: '',
selectSourceData: [],
categoryListSource: [],
}
}
// 数据初始化
componentDidMount() {
/
/ 获取categoryList数据,注意最好不要和service中函数名重复
// 设置筛选项
this.setState({
selectSourceData: selectData
})
};
// 获取 categoryList
getCategoryListFn = ( params ) => {
params = params ? params : { chanel: 'website' };  // 设置⼀个默认值,可随意⾃定义    getCategoryList({ ...params }).then(res => {  // 可以定义分页参数
if (res.status == 200 ) {
const { data } = res;
this.setState({
categoryListSource: data.list
})
}
});
}
// 切换筛选项
ant design selectChange = (value, attr) => {
// 双向绑定
this.setState({
[attr.key]: value
});
// ⾃定义其他操作
}
// 重置
onReset = () => {
this.setFields();
// 重置初始化
this.setState({
selectSourceData: selectData
})
};
// 搜索提交,请求list,更新table
onFinish = (values) => {
channel: values.channel || '',
})
}
// render
render() {
const columns = [
{
title: '推送时间',
dataIndex: 'push_time',
key: 'push_time',
align: 'center',
width: 150,
},
{
title: '事件名称',
dataIndex: 'event_name',
key: 'event_name',
align: 'center',
width: 150,
},
];
const { loading } = this.props;
const { dateRange, selectSourceData, categoryListSource} = this.state;
return (
<PageContainer>
<Card
className={styles.tabsCard}
>
<Form
layout="inline"
ref={this.formRef}
name="searchObj"
className={styles.formBox}
initialValues={{
channel: '',
dateRange: [],
}}
onFinish={Finish}
onReset={Reset}
>
{selectSourceData.map(item => (
<Form.Item
name={item.name}
label={item.label}
key={item.name}
className={styles.formItem}
>
<Select
value={item.name}
style={item.style}
placeholder="请选择"
disabled={item.disabled}
onChange={this.selectChange}
>
{item.options.map((val, index) => (
<Option key={index} disabled={val.disabled} type={item.name} value={val.value}>{val.name}</Option>
))}
</Select>
</Form.Item>
))}
<Form.Item
key='dateRange'
name="dateRange"
className={styles.formItem}
>
<RangePicker
value={dateRange.length ? [moment(dateRange[0], dateFormat), moment(dateRange[1], dateFormat)] : null}  // 重置设置
type="dateRange"
placeholder={['开始时间', '结束时间']}
format={dateFormat}
onChange={(value, dateString) => {
this.setState({
dateRange: dateString
})
}}
/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">搜索</Button>
</Form.Item>
<Form.Item>
<Button type="default" htmlType="reset">重置</Button>
</Form.Item>
</Form>
<Table
dataSource={categoryListSource}
bordered={true}
scroll={{ x: 2400 }}  // 超出滚动,最⼤宽度
columns={columns}
rowKey={(record, index) => index}
// pagination={pagination}
// pagination={false}
loading={loading}
// onChange={this.handleTableChange}
/>
</Card>
</PageContainer>
)
}
}
service.js
// 封装axios,interceptors
import request from '@/utils/request';
// 获取分类列表
export async function getCategoryList(params) {
return request('/admin/report/get-category-list', {
method: 'POST',
data: params,
});
}
⼆、编译可能出现警告:
 There are multiple modules with names that only differ in casing. This can lead to unexpected behavior when compiling on a filesystem with other case-semantic. Use equal casing. Compare these module identifiers
 1、新增⽂件夹名注意都要⼩写,如果多个单词,⽤横杠 — 隔开
 2、import 引⼊的⽂件注意⽂件名的⼤⼩写: impor request form '../utils/request.js'
 Each child in a list should have a unique "key" prop,Check this render methods of  'Body'
 1、如果是table组件,官⽅给 Table 组件提供了⼀个 rowKey 属性,⽤于给表格的每⼀⾏设定⼀个 key
<Table
dataSource={this.state.tableDataSource}
rowKey={(record, index) => index}  // 或者 record.id,index好像启⽤了,最好⽤唯⼀字段或者拼接字段
>
</Table>
 2、如果是 map() 循环,遍历的时候也必须给 key 值
{list.map((item, index) => {
<p key={index}>{{item}}</p>
})
}
Missing message: "menu.分类管理.分类列表" for locale: "zh-CN", using default message as fallback
这是菜单翻译缺少,请求的菜单需要同步更新
到 client -> src -> locales -> zh-CN -> menu.js
'menu.分类管理.分类列表': '分类列表',
 1、到 client -> defaultSettings.js,⾥⾯ menus 先注释掉
 2、到 client -> src -> layouts -> Basiclayout.jsx,到⾥⾯ ProLayout  标签,在 menuDataRender 属性配置上⾯加上配置 menu={{ loading }}
四、componentDidmount 获取⽗组件 this.props 中异步数据的失效
  这个时候,可以使⽤更新过程中⽣命周期 componentWillReceiveProps(nextProps) 来获取异步ajax请求的数据 nextProps
  1、在接受⽗组件改变后的 props 需要重新渲染组件时⽤到的⽐较多
  2、接受⼀个参数 nextProps
  3、通过对⽐ nextProps 和 this.props,将 nextProps 的state为当前组件的state,从⽽重新渲染组件
五、ant design 关于 Datepicker 限制时间范围和默认时间
1、限制时间范围
// 使⽤disbledDate,当前时间到前7天内选择时间, 关于moment.js参考官⽹
const disabledDate = (current) => {
// moment().subtract(7, "days") 表⽰当前⽇期往前推移7天
// moment().endOf( "day")  表⽰当前⽇期最后的时间23:59:59
return current && (current < moment().subtract(7, "days") || current >= moment().endOf('day')
}
<RangPicker disabledDate={this.disabledDate}>
2、默认时间
const dateFormat = 'YYYY-MM-DD';
this.state = {
// 当前时间到前30天内
dateRange: [moment().subtract(30, 'days'), moment()],
}
<RangePicker
value={dateRange.length ? [moment(dateRange[0], dateFormat), moment(dateRange[1], dateFormat)] : null}
type="dateRange"
format={dateFormat}
disabledDate={this.disabledDate}
>
</RangePicker>