一、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: {
'100px'
},
options: [
{
value: 'website',
name: '站内',
},
{
value: 'email',
name: '邮件',
}
]
},
];
// 创建类组件实例
class categoryList extends Component {
// 获取 DOM 元素节点,通过设置 ref,这里是表单form的ref
formRef = React.createRef();
constructor(props) {
super(props);
this.state = {
channel: '',
selectSourceData: [],
categoryListSource: [],
}
}
// 数据初始化
componentDidMount() {
// 获取categoryList数据,注意最好不要和service中函数名重复
this.getCategoryListFn();
// 设置筛选项
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
})
}
});
}
// 切换筛选项
selectChange = (value, attr) => {
// 双向绑定
this.setState({
[attr.key]: value
});
// 自定义其他操作
}
// 重置
onReset = () => {
this.formRef.current.resetFields();
// 重置初始化
this.setState({
selectSourceData: selectData
})
};
// 搜索提交,请求list,更新table
onFinish = (values) => {
this.getStatDataFn({
channel: values.channel || '',
})
}
// render
render() {
const columns = [
{
title: '推送时间',
dataIndex: 'push_time',
key: 'push_time',
align: 'center',
150,
},
{
title: '事件名称',
dataIndex: 'event_name',
key: 'event_name',
align: 'center',
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={this.onFinish}
onReset={this.onReset}
>
{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.分类管理.分类列表': '分类列表',
三、本地开发 menu 导航栏无法加载问题 (https://github.com/ant-design/ant-design-pro/issues/7530)
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参考官网 http://momentjs.cn/ 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>