一、登录功能:antd-Form、localStorage
1.登录界面与首页实现
1)两个界面路由注册,通过判断本地是否有用户登录数据
有:---> <Route path='/' component={Admin} /> (作为的根路径)
无:---> <Route path='/login' component={Login} />
2.表单数据收集
1)输入过程数据验证是否符合要求
2) 表单提交数据验证 --> 通过发起登录请求 --> 跳转到根路由
在这个过程中需要往本地存储用户信息,并通过memoryUtil 将数据传给首页显示
3. 首页排版:antd -- Layout
1)侧边栏菜单实现:通过数据遍历展现到页面
2)权限验证:根据用户menus数据,决定侧边栏菜单功能展示
3)头部
退出功能:antd --- Modal 、 退出后本地用户数据清除,跳转到登录路由
时间、天气动态展示:时间格式化Utils,高德天气接口
标题展示:根据当前路径匹配标题
4)home内容区:antd组件
二、 商品 ---- 品类管理:品类增加、修改、获取
1.接口准备
包括接口请求使用axios封装为一个函数,再分别创建不同类别的接口函数(reqAdd--、reqUpdate--)
目的:方便接口传参而避免造成代码冗余
//获取分类列表
export const reqCategoryList = (parentId)=> ajax('/manage/category/list',{parentId})
//添加分类列表
export const reqAddCategory = (parentId,categoryName)=> ajax('/manage/category/add',{parentId,categoryName},'POST')
//更新分类列表
export const reqUpdateCategory = (categoryId,categoryName)=> ajax('/manage/category/update',{categoryId,categoryName},'POST')
2. 品类管理路由组件实现--数据初始化
1)antd---Card模块---Table模块
2) 组件加载完后生命周期:请求数据(这是一个通用数据更新函数)、初始化数据
componentDidMount(){
this.inintColumns()
this.setCategory()
}
3)二级页面数据初始化:根据接口参数不同,请求不同数据(利用Table性质拿到对应点击数据 ),实现需要显示或隐藏部分
3. 品类管理路由组件实现--数据修改
1)antd---Modal模块---Form表单提交
2)拿到表单数据(函数传参setForm)---数据验证通过后调更新接口函数
updateCategory = ()=>{
const categoryId = this.category._id
//表单验证:通过后才处理
this.form.validateFields()
.then(async (values) =>{
//隐藏确认框
this.setState({
isModalVisible: 0,
})
const {categoryName} = values
//清空输入框
//this.form.resetFields()
const result = await reqUpdateCategory(categoryId,categoryName)
if(result.status === 0){
//重新展示类别列表
message.success('修改成功')
this.setCategory()
}
})
.catch((err)=>{
message.info('请输入分类名称')
})
}
3)注意:每次点击一项修改时,输入框都应该匹配对应修改项,这里需要:
a. 清除前一次输入内容
b. 传值:通过props,将放在实例的对应category : this.category 传给form表单
c. this.category 是在点击显示模态框的时候放在实例上的
//模态框部分 destroyOnClose={true} 清除上次表单内容
<Modal title="更新"
visible={isModalVisible===2? true:false}
onOk={this.updateCategory}
onCancel={this.handleCancel}
destroyOnClose={true}
>
<UpdateForm categoryName={name} setForm = {(form)=>{this.form = form}}/>
</Modal>
//表单部分 initialValue={categoryName} 初始值
<Form ref={this.formRef}>
<Item
name="categoryName"
initialValue={categoryName}
rules={[
{ required: true, message: '分类名称必须输入' },
]}
>
{/* ----注意 <Form.Item /> 只会对它的直接子元素绑定表单功能 */}
<Input placeholder="输入分类的名字" />
</Item>
</Form>
三、 商品 ---- 商品管理:商品增加、修改、详情
1. 商品列表初始化:antd-Table 来帮忙实现后台分页获取数据
请求获取商品接口,每次点击下一页时才发请求拿数据
注意:1)当页面初始化时,当前请求page为1,后台会返回total总数,table根据total页面展示页数
2)页面改变时会将当前页数作为回调传给接口继续获取下一页的数据
<Card title={title} extra={extra}>
<Table
dataSource={products}
columns={columns}
bordered
rowKey='_id'
loading={loading}
pagination= {{
defaultPageSize:PAGE_SIZE,
total,
onChange:(pageNum)=>{this.setProducts(pageNum)} // 页码改变的回调,参数是页码数和每页条数
}}
/>
</Card>
2. 页面功能:
1)按名称搜索、按内容搜索
收集select --value 和input内容:select与input绑定onChange监听回调,value改变即传入数据----this.setState
点击搜索,拿参数发请求
注意坑:
搜索出的列表页面会根据当前页面下标显示,所以需要在搜索的时候传初始参pageNum=1
这里的接口分为名称、内容两个,可合并处理,注意变量作为属性名
//搜索商品 (productName/productDesc)
export const reqSearchProducts = ({pageNum,pageSize,searchName,searchType})=> ajax('/manage/product/search',{
pageNum,
pageSize,
[searchType]:searchName
})
2)商品状态(上/下架)
得到当前点击商品数据,进行接口传参,商品status需取反
3)展示详情页
得到当前点击商品数据 ---- 传给详情组件(路由组件传数据 this.props.history.push('/product/detail',product)})
---- 所属分类需要根据parentId与categoryId获取(发请求) ---- 页面渲染
4)修改与添加功能,同一路由组件实现
① 点击修改时需展现当前商品信息,点击添加不需要,根据判断上级路由传没传参来决定修改还是添加
② 所属分类:使用antd --- Cascader实现(组件一加载需要初始化一级分类与二级分类)
③ 级联的二级分类是动态加载的
注意坑:更新状态值this.setState({})到时候 解构赋值
④ 商品图片上传:
添加时:antd-Upload 直接请求接口
修改时:需要初始化图片列表,将imgs数组传过来渲染到页面
<Upload
action="/manage/img/upload" // 上传请求接口
accept='image/*'//上传文件类型
name='image' //请求参数名
listType="picture-card"
fileList={fileList} //上传文件数量
onPreview={this.handlePreview} // 图片显示大图的回调
onChange={this.handleChange} // 图片上传过程中的回调
>
{fileList.length >= 2 ? null : uploadButton}
</Upload>
⑤ 富文本编辑器:react-draft-wysiwyg