一、登录功能: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