1.角色管理静态页面role/index.jsx
import React,{Component} from 'react'
import {
Card,
Button,
Table,
message
} from 'antd'
import {PAGE_SIZE} from '../../../utils/constans' //常量:分页每页显示多少条数据
export default class Role extends Component{
state={
roles:[
{"_id": "5ca9eaa1b49ef916541160d3",
"name": "测试",
"create_time": 1554639521749,
"__v": 0,
"auth_time": 1558679920395,
"auth_name": "test007"},
{"_id": "5ca9eaa1b49ef916541160d4",
"name": "产品",
"create_time": 1554639521749,
"__v": 0,
"auth_time": 1558679920395,
"auth_name": "test008"},
], //Table datasource
}
//初始化表格列标题,及对应的数据源,dataIndex:对应api返回的数据名
initColumns=()=>{
this.columns=[
{title:'角色名称',dataIndex:'name'},
{title:'创建时间',dataIndex:'create_time'},
{title:'授权时间',dataIndex:'auth_time'},
{title:'授权人',dataIndex:'auth_name'},
]
}
componentWillMount(){
this.initColumns()//运行初始表格列标题,及对应的数据源函数,把表格列数据赋值到this.columus上
}
render(){
const {roles}=this.state
//card的左侧 (Button的disabled:按钮不可用)
const title=(
<span>
<Button type='primary' style={{marginRight:8}}>创建角色</Button>
<Button type='primary' disabled>设置角色权限</Button>
</span>
)
return(
<Card title={title}>
<Table
bordered /**边框 */
rowKey='_id' /**表格行 key 的取值,可以是字符串或一个函数 */
dataSource={roles} /**数据源 */
columns={this.columns} /**列标题,及对应的数据源 */
pagination={{defaultPageSize:PAGE_SIZE}} /**分页设置默认分页数量 */
rowSelection={{type:'radio'}} /**第行前面加一个单选框antd文档找使用方法 */
/>
</Card>
)
}
}
效果 http://localhost:3000/role
2. api请求:获取所有角色列表
注:在请求前要先向数据库添加一些角色数据,可用getman,或直接数据库添加
1. api/index.js
//请求所有角色列表
export const reqRoles=()=>ajax(BASE+'/manage/role/list')
2. role/index.jsx
import {reqRoles} from '../../../api' //【1】
state={//【2】清空模拟数据
roles:[], //所有角色列表:连接Table datasource
}
//【3】获取角色列表数据,设置到state中
getRoles=async()=>{
const result=await reqRoles()
if(result.status===0){
const roles=result.data //把返回值赋值给roles
this.setState({
roles //定义的变量和state的roles同名,所以简写
})
}
}
componentDidMount(){
this.getRoles() //【4】函数:获取角色列表设置到state中
}
效果:同1步静态,但授权两项为空
http://localhost:3000/role
3.点击一行的任意位置选中单选框
onRow用法:https://3x.ant.design/components/table-cn/#onRow-用法
rowSelection用法:https://3x.ant.design/components/table-cn/#rowSelection
1.实现
【0】Table的onRow
控制点击当前行的行为
【1】点击角色列表对应行的行为
【2】设置state:选中的role
【3】把当前点击的行赋值到state里的role
【4】取出state的role
【6】Table的selectedRowKeys
根据4确定哪个是被选中状态;
state={
roles:[], //所有角色列表:连接Table datasource
role:{},//【2】选中的role
}
//【1】点击角色列表对应行的行为
onRow=(role)=>{
return{
onClick: event => { //点击行时执行以下
console.log('row onClick()', role)
this.setState({ //【3】把当前点击的行赋值到state里的role
role
})
}
}
}
//render和return间
const {roles,role}=this.state //【4】取出role
//return后:
<Card title={title}>
<Table
bordered /**边框 */
rowKey='_id' /**指定数据主键 */
dataSource={roles} /**数据源 */
columns={this.columns} /**列标题,及对应的数据源 */
pagination={{defaultPageSize:PAGE_SIZE}} /**分页设置默认分页数量 */
rowSelection={{type:'radio',selectedRowKeys:[role._id]} } /**【6】selectedRowKeys根据4确定哪个是被选中状态(请求的数据里有一个:"_id": "5e6b147106c64115446c4fb2",); 第行前面加一个单选框antd文档找使用方法 */
onRow={this.onRow} /**【0】控制点击当前行的行为 */
/>
</Card>
效果:点一行的任意地方都会选中单选框
2. 选中一行后,设置权限按钮变可点状态
const {roles,role}=this.state //【1】取出role
//card的左侧 (Button的disabled:按钮不可用【2】如果_id不存在则按钮不可用)
const title=(
<span>
<Button type='primary' style={{marginRight:8}}>创建角色</Button>
<Button type='primary' disabled={!role._id}>设置角色权限</Button>
</span>
)
效果 点任意一行 设置角色权限按钮变如下
二、添加角色弹窗
1.引入modal弹窗
import {
Card,
Button,
Table,
Modal, //【1】弹窗
message
} from 'antd'
state={
roles:[], //所有角色列表:连接Table datasource
role:{},//选中的role
isShowAdd: false, //【2】是否显示添加界面
}
//【render】
//card的左侧 (Button的disabled:按钮不可用)
const title=(
<span>
{/* 【3】点创建角色:显示创建角色的弹窗 */}
<Button type='primary' style={{marginRight:8}} onClick={()=>{this.setState({isShowAdd:true})}}>创建角色</Button>
<Button type='primary' disabled={!role._id}>设置角色权限</Button>
</span>
)
//【return】
{/* 【4】弹窗 */}
<Modal
title='添加角色'
visible={isShowAdd} /*弹窗可见状态*/
onOk={this.addRole} /*点ok提交信息*/
onCancel={()=>{this.setState({isShowAdd:false})}} /*点取消*/
>
</Modal>
2.创建角色页面把子组件form传给父组件index.jsx—当前role/addForm.jsx
import React,{Component} from 'react'
import{Form,Input} from 'antd'
import PropTypes from 'prop-types' //【1】传值模块
const Item =Form.Item
class AddForm extends Component{
static propTypes={
setForm:PropTypes.func.isRequired //【2】父组件传过来的接收子组件form对象的函数
}
componentWillMount () {
//【3】运行接收到的父组件传过来函数,把form传给父组件
this.props.setForm(this.props.form)
}
render(){
// 取出form的表单验证方法
const { getFieldDecorator } = this.props.form
// 【2.1】指定Item布局的配置对象
const formItemLayout = {
labelCol: { span: 4 }, // 左侧label的宽度
wrapperCol: { span: 15 }, // 右侧包裹的宽度
}
return(
<Form>
{/* 【2.2】把formItemLayout放入Item */}
<Item label='角色名称' {...formItemLayout}>
{
getFieldDecorator('roleName', {
initialValue: '',
rules: [
{required: true, message: '角色名称必须输入'}
]
})(
<Input placeholder='请输入角色名称'/>
)
}
</Item>
</Form>
)
}
}
export default Form.create()(AddForm) //包装AddForm组件使具体form相关方法
3.role/index.jsx向addForm.jsx发送setForm函数接收其传过来的from表单
{/* 弹窗 */}
<Modal
title='添加角色'
visible={isShowAdd} /*弹窗可见状态*/
onOk={this.addRole} /*点ok提交信息*/
onCancel={()=>{this.setState({isShowAdd:false})}} /*点取消*/
>
{/* 【1】传递子组件form的函数setForm:(接收一个参数form,令当前组件的form=传过来的form*/}
<AddForm setForm={(form) => this.form = form} />
</Modal>
4.添加角色api接口api/index.jsx
// 添加角色
export const reqAddRole=(roleName)=>ajax(BASE+'/manage/role/add',{roleName},'POST')
5.引入接口,并执行添加角色role/index.jsx
import {reqRoles,reqAddRole} from '../../../api' //【1】添加角色api
//state下
//【2】点添加角色弹窗的ok按钮:添加角色
addRole=()=>{
this.form.validateFields(async(err,value)=>{
if(!err){
console.log(value)
//隐藏确认框
this.setState({isShowAdd:false})
//收集数据
const {roleName}=value
this.form.resetFields()//清空表单内数据,方便下次使用
//添加角色请求
const result=await reqAddRole(roleName)
if(result.status===0){
message.success('角色添加成功')
//取出返回的新增role值
const role=result.data
//更新roles状态,使新增的角色显示出来(基于原本状态数据更新)
/*不建议的写法(虽然也能实现)
const roles = this.state.roles
roles.push(role)
this.setState({
roles
})*/
this.setState(state=>({
roles:[...state.roles,role]
}))
}else{
message.error('角色添加失败')
}
}
})
}
★知识点:setState的真正用法
this.setState((state,props)=>({
roles:[...state.roles,role]
}))
效果:http://localhost:3000/role
输入角色,点ok后提交角色,显示添加角色成功;点cacel关闭弹窗
优化点cancel后,再点创建角色上次的东西还在里面
this.form.resetFields()
//【优化】取消时顺便清空表单方便下次使用
{/* 添加角色弹窗 */}
<Modal
title='添加角色'
visible={isShowAdd} /*弹窗可见状态*/
onOk={this.addRole} /*点ok提交信息*/
onCancel={()=>{
this.setState({isShowAdd:false})
this.form.resetFields()//【优化】取消时顺便清空表单方便下次使用
}} /*点取消*/
>
{/* 传递子组件form的函数setForm:(接收一个参数form,令当前组件的form=传过来的form) */}
<AddForm setForm={(form) => this.form = form} />
</Modal>
三、设置角色权限
1.设置权限弹窗role/index.jsx
import AuthForm from './authForm' //【4】设置权限弹窗的表单
//class ...
state={
roles:[], //所有角色列表:连接Table datasource
role:{},//选中的role
isShowAdd: false, //是否显示添加角色弹窗
isShowAuth:false, //【0】是否显示设置权限弹窗
}
//render
const {roles,role,isShowAdd,isShowAuth}=this.state //【1】取出isShowAuth
//card的左侧 (Button的disabled:按钮不可用)
const title=(
<span>
{/* 【3】点设置权限:显示对应弹窗onClick={()=>{this.setState({isShowAuth:true})}}*/}
<Button type='primary' style={{marginRight:8}} onClick={()=>{this.setState({isShowAdd:true})}}>创建角色</Button>
<Button type='primary' disabled={!role._id} onClick={()=>{this.setState({isShowAuth:true})}}>设置角色权限</Button>
</span>
)
//return内
{/* 【2】设置权限弹窗 */}
<Modal
title='设置权限'
visible={isShowAuth} /*弹窗可见状态*/
onOk={this.addAuth} /*点ok提交信息*/
onCancel={()=>{
this.setState({isShowAuth:false})
}} /*点取消*/
>
{/* */}
<AuthForm />
</Modal>
2.创建设置权限弹窗内容authForm.jsx
import React,{Component} from 'react'
import {Form,Input,Tree} from 'antd'
const Item=Form.Item
export default class AuthForm extends Component{
render(){
// 指定Item布局的配置对象
const formItemLayout = {
labelCol: { span: 4 }, // 左侧label的宽度
wrapperCol: { span: 15 }, // 右侧包裹的宽度
}
return(
<div>
<Item label='角色名称' {...formItemLayout}>
<Input />
</Item>
</div>
)
}
}
效果:http://localhost:3000/role
3.显示选中的角色名称
1.role/index.jsx把role传递给authForm.jsx
//render
const {roles,role,isShowAdd,isShowAuth}=this.state //【1】娶出role
//return...
{/*【2】把role传递给子组件 */}
<AuthForm role={role} />
2.authForm.jsx接收index传过来的role数据并显示
import PropTypes from 'prop-types' //【1】
//class ..
static propTypes={//【2】
role:PropTypes.object
}
//render
//【3】
const {role}=this.props
//return
<Item label='角色名称' {...formItemLayout}>
{/* 【4】显示选中的角色名,并让它呈不可编辑的状态 */}
<Input value={role.name} disabled />
</Item>
效果:http://localhost:3000/role
点设置角色权限
4.显示树形结构
antd Tree用法:https://3x.ant.design/components/tree-cn/
4.1显示静态tree
import menuList from '../../../config/menuConfig' //【1】导入菜单列表
const { TreeNode } = Tree //【2】拿出TreeNode
//class
//return
{/* 【3】到antd复制一个tree进行修改 */}
<Tree
checkable
defaultExpandAll={true} /*默认展开所有节点*/
>
<TreeNode title="parent 1" key="0-0">
<TreeNode title="parent 1-0" key="0-0-0" >
<TreeNode title="leaf" key="0-0-0-0" />
<TreeNode title="leaf" key="0-0-0-1" />
</TreeNode>
<TreeNode title="parent 1-1" key="0-0-1">
<TreeNode title='sss' key="0-0-1-0" />
</TreeNode>
</TreeNode>
</Tree>
效果:
4.2 显示菜单列表Tree
import menuList from '../../../config/menuConfig' //【1】导入菜单列表
//【2】获取菜单列表
getTreeNodes=(menuList)=>{
//代替map函数:reduce((初始值pre,当前正在处理的数组item)={},初始值[])
return menuList.reduce((pre,item)=>{
pre.push(
<TreeNode title={item.title} key={item.key}>
{/* 如果有children则调用本函数,把children再运行一次 */}
{item.children ? this.getTreeNodes(item.children):null}
</TreeNode>
)
return pre
},[])
}
//【3】在页面加载前调用一次菜单
componentWillMount(){
this.treeNodes=this.getTreeNodes(menuList)
}
【return】
{/* 到antd复制一个tree进行修改 */}
<Tree
checkable
defaultExpandAll={true} /*默认展开所有节点*/
>
{/* 【4】外面包个根节点,平台权限,内调用3步的treeNodes */}
<TreeNode title='平台权限' key='all'>
{this.treeNodes}
</TreeNode>
</Tree>
效果:
5.获取当前Tree的选中状态,及改变选中状态authForm.jsx
#【class】
constructor(props){
super(props)
//【1】根据传入的角色生成初始状态
const {menus} = this.props.role
this.state={
checkedKeys:menus
}
}
static propTypes={// 【0】接收父传值
role:PropTypes.object
}
//【5】更新Tree的选中状态
onCheck=(checkedKeys)=>{
console.log('oncheck:',checkedKeys)
this.setState({checkedKeys})
}
#【render()】
//【2】取出Tree要选中的节点
const {checkedKeys}=this.state
#【return】
{/* 到antd复制一个tree进行修改 */}
<Tree
checkable
defaultExpandAll={true} /*默认展开所有节点*/
checkedKeys={checkedKeys} /*【3】控制哪些节点为选中状态*/
onCheck={this.onCheck} /*【4】点击后更改选中状态*/
>
{/* 外面包个根节点,平台权限,内调用3步的treeNodes */}
<TreeNode title='平台权限' key='all'>
{this.treeNodes}
</TreeNode>
</Tree>
效果:选中节点后状态会对应变化
6. 更新角色(父子传值等)
1.role/index.jsx更新角色
import {reqRoles,reqAddRole,reqUpdateRole} from '../../../api' //【7】引入更新角色函数requpdaterole; 添加角色api
//class
constructor (props) {
super(props)
//【1】创建一个auth的ref用于父子组件传值
this.auth = React.createRef()
}
// 【4】更新角色:点设置权限弹窗里的ok操作
updateRole=async()=>{//【9】加async
// 隐藏确认框
this.setState({isShowAuth: false})
const role=this.state.role
//【5】得到最新的menus => 到authForm.jsx里传值过来(getMenus = () => this.state.checkedKeys)
const menus=this.auth.current.getMenus()
//【6】把接收过来的菜单传给当前role.menus => 到api/index.js里写更新角色接口函数
role.menus=menus
//【8】发送更新请求
console.log(role)
const result = await reqUpdateRole(role)
if (result.status===0){
message.success('设置角色权限成功!')
this.getRoles()
}else{
message.error('更新角色权限失败')
}
}
//render()
//return
{/* 设置权限弹窗 */}
<Modal
title='设置权限'
visible={isShowAuth} /*弹窗可见状态*/
onOk={this.updateRole} /*【3】点ok提交信息*/
onCancel={()=>{this.setState({isShowAuth:false})}} /*点取消*/
>
{/*【2】把this.auth传给子组件 把role传递给子组件 */}
<AuthForm ref={this.auth} role={role} />
</Modal>
2. authForm.jsx传值
//【1】为父组件提交获取最新menus数据的方法:把state.checkedKeys传给父组件
getMenus = () => this.state.checkedKeys
3.api/index.js接口
// 更新角色,传过来的参数就是字典格式,所以role参数不用加花括号
export const reqUpdateRole=(role)=>ajax(BASE+'/manage/role/update',role,'POST')
效果:
勾选后会设置权限成功
7.优化:当更新过一个角色权限后,其它的角色会变的跟这个角色一样,原因是:收到父组件传的props值后,state内数据没更新authForm.jsx
//【2】根据新传入的role来更新checkedKeys状态当组件接收到新的属性时自动调用
componentWillReceiveProps (nextProps) {
console.log('componentWillReceiveProps()', nextProps)
const menus = nextProps.role.menus
this.setState({
checkedKeys: menus
})
// this.state.checkedKeys = menus //也可以这样写
}
效果:更新一个角色后,其它角色不会变的跟当前一样
8.授权时间,授权人优化role/index.jsx
【2】添加授权时间及授权人
import memoryUtils from '../../../utils/memoryUtils' //【1】引入记忆模块用于显示用户名
// 更新角色:点设置权限弹窗里的ok操作
updateRole=async()=>{//加async
// 隐藏确认框
this.setState({isShowAuth: false})
const role=this.state.role
//得到最新的menus => 到authForm.jsx里传值过来(getMenus = () => this.state.checkedKeys)
const menus=this.auth.current.getMenus()
//把接收过来的菜单传给当前role.menus => 到api/index.js里写更新角色接口函数
role.menus=menus
//【2】添加授权时间及授权人
role.auth_time=Date.now()
role.auth_name = memoryUtils.user.username
//发送更新请求
console.log(role)
const result = await reqUpdateRole(role)
if (result.status===0){
message.success('设置角色权限成功!')
this.getRoles()
}else{
message.error('更新角色权限失败')
}
}
效果:设置权限后,会显示对应时间及授权人
9.把时间戳格式化成字符串形式方便人类查看
0.附:时间格式函数 utils/dateutils.js
//包含n个日期时间处理的工具函数模块
//格式化日期
export function formateDate(time) {
if (!time) return ''
let date = new Date(time)
return date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate()
+ ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds()
}
1.格式化时间role/index.jsx
全写:render:(create_time)=>formateDate(create_time)
简写:render:formateDate
import {formateDate} from '../../../utils/dateUtils' //【1】时间格式化
//初始化表格列标题,及对应的数据源,dataIndex:对应api返回的数据名
initColumns=()=>{
//【2】调用函数格式化时间戳
this.columns=[
{title:'角色名称',dataIndex:'name'},
{title:'创建时间',dataIndex:'create_time',render:(create_time)=>formateDate(create_time)},
{title:'授权时间',dataIndex:'auth_time',render:formateDate},
{title:'授权人',dataIndex:'auth_name'},
]
}
效果:时间会变成可读
附件:完整代码/role/
index.jsx
import React,{Component} from 'react'
import {
Card,
Button,
Table,
Modal, //弹窗
message
} from 'antd'
import {PAGE_SIZE} from '../../../utils/constans'
import {reqRoles,reqAddRole,reqUpdateRole} from '../../../api' //引入更新角色函数requpdaterole; 添加角色api
import AddForm from './addForm' //添加角色弹窗的表单
import AuthForm from './authForm' //设置权限弹窗的表单
import memoryUtils from '../../../utils/memoryUtils' //引入记忆模块用于显示用户名
import {formateDate} from '../../../utils/dateUtils' //【1】时间格式化
export default class Role extends Component{
constructor (props) {
super(props)
//创建一个auth的ref用于父子组件传值
this.auth = React.createRef()
}
state={
roles:[], //所有角色列表:连接Table datasource
role:{},//选中的role
isShowAdd: false, //是否显示添加角色弹窗
isShowAuth:false, //是否显示设置权限弹窗
}
//点击角色列表对应行的行为
onRow=(role)=>{
return{
onClick: event => { //点击行时执行以下
console.log('row onClick()', role)
this.setState({ //把当前点击的行赋值到state里的role
role
})
}
}
}
//获取角色列表数据,设置到state中
getRoles=async()=>{
const result=await reqRoles()
if(result.status===0){
const roles=result.data
this.setState({
roles
})
}
}
//初始化表格列标题,及对应的数据源,dataIndex:对应api返回的数据名
initColumns=()=>{
//【2】调用函数格式化时间戳
this.columns=[
{title:'角色名称',dataIndex:'name'},
{title:'创建时间',dataIndex:'create_time',render:(create_time)=>formateDate(create_time)},
{title:'授权时间',dataIndex:'auth_time',render:formateDate},
{title:'授权人',dataIndex:'auth_name'},
]
}
//点添加角色弹窗的ok按钮:添加角色
addRole=()=>{
this.form.validateFields(async(err,value)=>{
if(!err){
console.log(value)
//隐藏确认框
this.setState({isShowAdd:false})
//收集数据
const {roleName}=value
this.form.resetFields()//清空表单内数据,方便下次使用
//添加角色请求
const result=await reqAddRole(roleName)
if(result.status===0){
message.success('角色添加成功')
//取出返回的新增role值
const role=result.data
//更新roles状态,使新增的角色显示出来(基于原本状态数据更新)
this.setState(state=>({
roles:[...state.roles,role]
}))
}else{
message.error('角色添加失败')
}
}
})
}
// 更新角色:点设置权限弹窗里的ok操作
updateRole=async()=>{//加async
// 隐藏确认框
this.setState({isShowAuth: false})
const role=this.state.role
//得到最新的menus => 到authForm.jsx里传值过来(getMenus = () => this.state.checkedKeys)
const menus=this.auth.current.getMenus()
//把接收过来的菜单传给当前role.menus => 到api/index.js里写更新角色接口函数
role.menus=menus
//【2】添加授权时间及授权人
role.auth_time=Date.now()
role.auth_name = memoryUtils.user.username
//发送更新请求
console.log(role)
const result = await reqUpdateRole(role)
if (result.status===0){
message.success('设置角色权限成功!')
this.getRoles()
}else{
message.error('更新角色权限失败')
}
}
componentWillMount(){
this.initColumns() //函数:运行初始表格列标题,及对应的数据源函数,把表格列数据赋值到this.columus上
}
componentDidMount(){
this.getRoles() //函数:获取角色列表设置到state中
}
render(){
const {roles,role,isShowAdd,isShowAuth}=this.state //娶出role; 取出isShowAuth
//card的左侧 (Button的disabled:按钮不可用)
const title=(
<span>
{/* 点创设置权限:显示对应弹窗; 点创建角色:显示创建角色的弹窗 */}
<Button type='primary' style={{marginRight:8}} onClick={()=>{this.setState({isShowAdd:true})}}>创建角色</Button>
<Button type='primary' disabled={!role._id} onClick={()=>{this.setState({isShowAuth:true})}}>设置角色权限</Button>
</span>
)
return(
<Card title={title}>
<Table
bordered /**边框 */
rowKey='_id' /**表格行 key 的取值,可以是字符串或一个函数 */
dataSource={roles} /**数据源 */
columns={this.columns} /**列标题,及对应的数据源 */
pagination={{defaultPageSize:PAGE_SIZE}} /**分页设置默认分页数量 */
rowSelection={{type:'radio',selectedRowKeys:[role._id]} } /**selectedRowKeys根据4确定哪个是被选中状态; 第行前面加一个单选框antd文档找使用方法 */
onRow={this.onRow} /**控制点击当前行的行为 */
/>
{/* 添加角色弹窗 */}
<Modal
title='添加角色'
visible={isShowAdd} /*弹窗可见状态*/
onOk={this.addRole} /*点ok提交信息*/
onCancel={()=>{
this.setState({isShowAdd:false})
this.form.resetFields()//取消时顺便清空表单方便下次使用
}} /*点取消*/
>
{/* 传递子组件form的函数setForm:(接收一个参数form,令当前组件的form=传过来的form) */}
<AddForm setForm={(form) => this.form = form} />
</Modal>
{/* 设置权限弹窗 */}
<Modal
title='设置权限'
visible={isShowAuth} /*弹窗可见状态*/
onOk={this.updateRole} /*点ok提交信息*/
onCancel={()=>{this.setState({isShowAuth:false})}} /*点取消*/
>
{/*把this.auth传给子组件 把role传递给子组件 */}
<AuthForm ref={this.auth} role={role} />
</Modal>
</Card>
)
}
}
2.addForm.jsx
import React,{Component} from 'react'
import{Form,Input} from 'antd'
import PropTypes from 'prop-types' //【1】传值模块
const Item =Form.Item
class AddForm extends Component{
static propTypes={
setForm:PropTypes.func.isRequired //【2】父组件传过来的接收子组件form对象的函数
}
componentWillMount () {
//【3】运行接收到的父组件传过来函数,把form传给父组件
this.props.setForm(this.props.form)
}
render(){
// 取出form的表单验证方法
const { getFieldDecorator } = this.props.form
// 【2.1】指定Item布局的配置对象
const formItemLayout = {
labelCol: { span: 4 }, // 左侧label的宽度
wrapperCol: { span: 15 }, // 右侧包裹的宽度
}
return(
<Form>
{/* 【2.2】把formItemLayout放入Item */}
<Item label='角色名称' {...formItemLayout}>
{
getFieldDecorator('roleName', {
initialValue: '',
rules: [
{required: true, message: '角色名称必须输入'}
]
})(
<Input placeholder='请输入角色名称'/>
)
}
</Item>
</Form>
)
}
}
export default Form.create()(AddForm) //包装AddForm组件使具体form相关方法
3.authForm.jsx
import React,{Component} from 'react'
import {Form,Input,Tree} from 'antd'
import PropTypes from 'prop-types' //父子传值
import menuList from '../../../config/menuConfig' //导入菜单列表
const Item=Form.Item
const { TreeNode } = Tree //拿出TreeNode
export default class AuthForm extends Component{
constructor(props){
super(props)
//根据传入的角色生成初始状态
const {menus} = this.props.role
this.state={
checkedKeys:menus
}
}
static propTypes={// 接收父传值
role:PropTypes.object
}
//获取菜单列表
getTreeNodes=(menuList)=>{
//代替map函数:reduce((初始值pre,当前正在处理的数组item)={},初始值[])
return menuList.reduce((pre,item)=>{
pre.push(
<TreeNode title={item.title} key={item.key}>
{/* 如果有children则调用本函数,把children再运行一次 */}
{item.children ? this.getTreeNodes(item.children):null}
</TreeNode>
)
return pre
},[])
}
//更新Tree的选中状态
onCheck=(checkedKeys)=>{
console.log('oncheck:',checkedKeys)
this.setState({checkedKeys})
}
//【1】为父组件提交获取最新menus数据的方法:把state.checkedKeys传给父组件
getMenus = () => this.state.checkedKeys
//在页面加载前调用一次菜单
componentWillMount(){
this.treeNodes=this.getTreeNodes(menuList)
}
//【2】根据新传入的role来更新checkedKeys状态当组件接收到新的属性时自动调用
componentWillReceiveProps (nextProps) {
console.log('componentWillReceiveProps()', nextProps)
const menus = nextProps.role.menus
this.setState({
checkedKeys: menus
})
// this.state.checkedKeys = menus
}
render(){
//取出Tree要选中的节点
const {checkedKeys}=this.state
// 取出role
const {role}=this.props
// 指定Item布局的配置对象
const formItemLayout = {
labelCol: { span: 4 }, // 左侧label的宽度
wrapperCol: { span: 15 }, // 右侧包裹的宽度
}
return(
<div>
<Item label='角色名称' {...formItemLayout}>
{/* 显示选中的角色名,并让它成不可编辑的状态 */}
<Input value={role.name} disabled />
</Item>
{/* 到antd复制一个tree进行修改 */}
<Tree
checkable
defaultExpandAll={true} /*默认展开所有节点*/
checkedKeys={checkedKeys} /*控制哪些节点为选中状态*/
onCheck={this.onCheck} /*点击后更改选中状态*/
>
{/* 外面包个根节点,平台权限,内调用3步的treeNodes */}
<TreeNode title='平台权限' key='all'>
{this.treeNodes}
</TreeNode>
</Tree>
</div>
)
}
}
3.utils/memoryUtils.jsx
/*
用于在内存中保存数据的工具模块
*/
export default{
user:{},
}
4.api/index.js
import ajax from './ajax'
import jsonp from 'jsonp'
import {message} from 'antd' //借用antd返回信息组件
// const BASE = 'http://localhost:5000'
const BASE = ''
//导出一个函数,第1种写法
//登录接口函数
// export function reqLogin(username,password){
// return ajax('login',{username,password},'POST')
// }
//导出一个函数,第2种写法
// 登录接口函数
export const reqLogin=(username,password)=>ajax(BASE+'login',{username,password},'POST')
//获取产品一级/二级分类列表接口
export const reqCategorys=(parentId)=>ajax(BASE+'/manage/category/list',{parentId})
//添加产品分类接口
export const reqAddCategory=(parentId,categoryName)=>ajax(BASE+'/manage/category/add',{parentId,categoryName},'POST')
//修改产品分类接口
export const reqUpdateCategory=({categoryId,categoryName})=>ajax(BASE+'/manage/category/update',{categoryId,categoryName},'POST')
//根据分类Id获取一个分类
export const reqCategory = (categoryId) => ajax(BASE + '/manage/category/info', {categoryId})
//获取产品列表
export const reqProducts=(pageNum,pageSize)=>ajax(BASE+'/manage/product/list',{pageNum,pageSize})
//产品上下架
export const reqUpdateStatus=(productId,status)=>ajax(BASE+'/manage/product/updateStatus',{productId,status},'POST')
/*搜索商品分页列表 (根据商品名称/商品描述)
searchType(搜索的类型): productName/productDesc*/
export const reqSearchProducts = ({pageNum, pageSize, searchName, searchType}) => ajax(BASE + '/manage/product/search', {
pageNum,
pageSize,
[searchType]: searchName,
})
//添加商品/修改商品:二合一接口,如果参数存在._id则为修改商品,否则为添加商品
export const reqAddUpdatePro=(product)=>ajax(BASE+'/manage/product/'+(product._id?'update':'add'),product,'POST')
// 删除服务器上指定名称图片
export const reqDeletPic=(name)=>ajax(BASE+'/manage/img/delete',{name},'POST')
//请求所有角色列表
export const reqRoles=()=>ajax(BASE+'/manage/role/list')
// 添加角色
export const reqAddRole=(roleName)=>ajax(BASE+'/manage/role/add',{roleName},'POST')
// 更新角色,传过来的参数就是字典格式,所以role参数不用加花括号
export const reqUpdateRole=(role)=>ajax(BASE+'/manage/role/update',role,'POST')
// 天气接口
export const reqWeather=(city) => {
const url = `http://api.map.baidu.com/telematics/v3/weather?location=${city}&output=json&ak=3p49MVra6urFRGOT9s8UBWr2`
//返回一个promise函数
return new Promise((resolve,reject) => {
//发送一个jsonp请求
jsonp(url,{},(err,data) => {
//输出请求的数据到控制台
console.log('jsonp()', err, data)
//如果请求成功
if(!err && data.status==='success'){
//从数据中解构取出图片、天气
const {dayPictureUrl,weather}=data.results[0].weather_data[0]
//异步返回图片、天气给调用函数者
resolve({dayPictureUrl,weather})
}else{//如果请求失败
message.error('天气信息获取失败')
}
})
})
}
//reqWeather('上海')
5. utils/storageUtils.js
/*
进行local数据存储管理的工具模块
*/
import store from 'store'
const USER_KEY = 'user_key'
export default {
/*保存user*/
saveUser (user) {
// localStorage.setItem(USER_KEY, JSON.stringify(user))
store.set(USER_KEY, user)
},
/*读取user*/
getUser () {
// return JSON.parse(localStorage.getItem(USER_KEY) || '{}')
return store.get(USER_KEY) || {}
},
/*删除user*/
removeUser () {
// localStorage.removeItem(USER_KEY)
store.remove(USER_KEY)
}
}