(记录笔记13)——13.1 权限设置

一 权限菜单设计

以下内容来自原创发布于慕课网 ,转载请注明出处,谢谢合作

1.权限的作用意义

顾名思义,“权”代表“权力”,划分了系统的职权,不同的用户拥有不同的权力划分;“限”代表“限制”,在权力划分的基础上对职能范围进行了限制,本文所述的权限相对简单,赋予不同角色看到不同菜单的权限。

权限控制能较好地解决系统安全问题,避免公司机密资料外泄,同时,不同部门使用系统时互不干扰,因此被企业广泛应用。

2.梳理用户、角色的概念

(1)用户

用户是指系统的登录用户,可以理解为一系列的人员,例如登录用户为张三、李四、王五和肖六这几个人。

(2)角色

角色指用户在系统中担任的角色,是系统赋予用户的头衔,例如A公司后台系统角色可以定义为:总裁、经理、员工。

3.选择合适的权限模型

(1)传统的权限模型

在早期,传统的权限模型就是为用户分配菜单权限,例如张三看到A、B、C菜单,李四看到B、C菜单,王五和肖六看到A、B、C菜单,这种传统的权限模型简单粗暴,直接为用户分配菜单即可,但是随着公司员工激增,在动则数百人的公司里,没一个员工都要分配一次,显然效率太低。

并且,在进行交互设计时,定义数百名用户拥有的菜单权限,那需要写数百行的表格。

img

(2)RBAC权限模型

RBAC,即基于角色的访问控制(Role-Based Access Control),是优秀的权限控制模型,主要通过角色和权限建立管理,再赋予用户不同的角色,来实现权限控制的目标。

利用该模型来配置权限,直接优点是角色的数量比用户的数量更少,先把权限赋予角色,即可完成权限的分配;再为用户分配相应的角色,即可直接获得角色拥有的权限。

交互设计的福音,只需定义有限的角色拥有哪些菜单权限即可。

img

(3)模型其他注意事项

在选择第二种RBAC权限模型时,需要注意,用户——角色——权限之间并非是一对一的对应关系,例如,一个用户可以拥有多种角色,一个角色也可以拥有多个权限,所以应该是多对多的关系,需要和开发说明清楚。

img

4.菜单实现效果

如图所示,通过权限控制后,不同用户登录进去看到的菜单显示都不一致,基于角色来进行菜单展示。

(1)总裁角色,菜单A、B、C

img

(2)经理角色,菜单B、C

img

(2)员工角色,菜单C

img

作者:河畔一角

链接:http://www.imooc.com/article/40553#

来源:慕课网

本文原创发布于慕课网 ,转载请注明出处,谢谢合作

二 权限模块的搭建

Github地址

/role/list 角色列表

{
  "code": 0,
  "result": {
    "page": 1,
    "page_size": 10,
    "total_count": 25,
    "page_count": 3,
    "item_list|7": [{
      "id|+1": 1,
      "role_name": /(管理人员)|(客服专员)|(财务专员)|(市场专员)|(人力专员)|(研发)|(测试)|(系统管理员)/,
      "status|0-1": 1,
      "authorize_user_name": "@cname",
      "authorize_time": 1521270166000,
      "create_time": 1499305790000,
      "menus": ["/admin/home", "/admin/ui/buttons", "/admin/ui/modals", "/admin/ui/loadings", "/admin/ui/notification", "/admin/ui/messages", "/admin/ui/tabs", "/admin/ui/gallery", "/admin/ui/carousel", "/admin/ui"]
    }]
  }
}

2.1 项目搭建

  • 创建Table表格注意添加以下属性:
    • dataSource={this.state.list}
    • columns={columns}

permission->index.js :对应路由 /pages/permission

// src/pages/permission/index.js
import React from 'react';
import {Card, Button,} from 'antd';


export default class PermissionUser extends React.Component {

  state = {};

  render() {
    return (
      <div>

      </div>
    );
  }
}   
// src/pages/permission/index.js
import React from 'react';
import {Card, Button,} from 'antd';
import ETable from './../../components/ETable';
import Utils from './../../utils/utils';
import axios from './../../axios';

export default class PermissionUser extends React.Component {

  state = {};

  componentWillMount() { // 通过生命周期函数加载接口
    axios.requestList(this, '/role/list', {}, true);
  }

  render() {
    const columns = [
      {
        title: '角色ID',
        dataIndex: 'id'
      }, {
        title: '角色名称',
        dataIndex: 'role_name'
      }, {
        title: '创建时间',
        dataIndex: 'create_time',
        render: Utils.formateDate
      }, {
        title: '使用状态',
        dataIndex: 'status',
        render(status) {
          return status == 1 ? '停用' : '启用';
        }
      }, {
        title: '授权时间',
        dataIndex: 'authorize_time',
        render: Utils.formateDate
      }, {
        title: '授权人',
        dataIndex: 'authorize_user_name'
      }
    ];
    console.log(this.state.list);
    return (
      <div>
        <Card>
          <Button type="primary" onClick={this.handleClearContent}>创建角色</Button>
          <Button type="primary" style={{marginLeft: 10, marginRight: 10}}>设置权限</Button>
          <Button type="primary">用户授权</Button>
        </Card>
        <div className="content-wrap">
          <ETable
            dataSource={this.state.list}
            columns={columns}
            updateSelectedItem={Utils.updateSelectedItem.bind(this)}
            selectedRowKeys={this.state.selectedRowKeys}
            selectedItem={this.state.selectedItem}
          />
        </div>
      </div>
    );
  }
}   

2.2 创建角色功能

为创建角色功能按钮增加点击事件, 使其弹框

role/create 角色创建

{
  "code": 0
}
  • 创建角色:Modal弹框中嵌入表单子组件

  • Modal弹框中应用表单组件:

    通过wrappedComponentRef={(inst) => this.roleForm = inst }获取表单元素的数据对象

  • 点击【创建角色】按钮弹出弹框:

    给onClick事件绑定this.handleRole(),设置this.state.isRoleVisible为true

  • 点击【OK】提交创建角色:

    给onOk事件绑定this.handleRoleSubmit()。

    • ①通过this.roleForm.props.form.getFieldsValue()获取表单的值,赋给params;
    • ②接口访问成功后,关闭弹框,刷新列表数据。
// src/pages/permission/index.js
import React from 'react';
import {Card, Button, Form, Modal, Input, Select} from 'antd';
import ETable from './../../components/ETable';
import Utils from './../../utils/utils';
import axios from './../../axios';

const FormItem = Form.Item;
const Option = Select.Option;
export default class PermissionUser extends React.Component {

  state = {
    isRoleVisible: false
  };

  componentWillMount() { // 通过生命周期函数加载接口
    axios.requestList(this, '/role/list', {}, true);
  }

  requestList = () => {
    axios.requestList(this, '/role/list', {}, true);
  };

  // 打开创建角色弹框
  handleRole = () => {
    this.setState({
      isRoleVisible: true,
    });
  };

  // 角色提交
  handleRoleSubmit = () => {
    const data = this.roleForm.props.form.getFieldsValue();
    console.log(data);
    axios.ajax({
      url: '/role/create', // //Easy Mock中只有{"code": 0}
      data: {
        params: data
      }
    }).then((res) => {
      if (res.code == 0) {
        this.setState({
          isRoleVisible: false   //关闭弹框
        });
        this.roleForm.props.form.resetFields()// 调用表单重置(清空表单数据)
        this.requestList();  //刷新列表数据
      }
    });
  };

  render() {
    const columns = [
      {
        title: '角色ID',
        dataIndex: 'id'
      }, {
        title: '角色名称',
        dataIndex: 'role_name'
      }, {
        title: '创建时间',
        dataIndex: 'create_time',
        render: Utils.formateDate
      }, {
        title: '使用状态',
        dataIndex: 'status',
        render(status) {
          return status == 1 ? '停用' : '启用';
        }
      }, {
        title: '授权时间',
        dataIndex: 'authorize_time',
        render: Utils.formateDate
      }, {
        title: '授权人',
        dataIndex: 'authorize_user_name'
      }
    ];
    return (
      <div>
        <Card>
          <Button type="primary" onClick={this.handleRole}>创建角色</Button>
          <Button type="primary" style={{marginLeft: 10, marginRight: 10}}>设置权限</Button>
          <Button type="primary">用户授权</Button>
        </Card>
        <div className="content-wrap">
          <ETable
            dataSource={this.state.list}
            columns={columns}
            updateSelectedItem={Utils.updateSelectedItem.bind(this)}
            selectedRowKeys={this.state.selectedRowKeys}
            selectedItem={this.state.selectedItem}
          />
        </div>
        <Modal
          title="创建角色"
          visible={this.state.isRoleVisible}
          onOk={this.handleRoleSubmit}
          onCancel={() => {
            this.roleForm.props.form.resetFields(); // 表单重置
            this.setState({
              isRoleVisible: false,
            });
          }}
        >
          <RoleForm wrappedComponentRef={(inst) => {
            this.roleForm = inst;
          }}/>
        </Modal>
      </div>
    );
  }


}

// 子组件一-------角色绑定
class RoleForm extends React.Component {
  render() {
    const formItemLayout = {
      labelCol: {
        span: 5
      },
      wrapperCol: {
        span: 19
      }
    };
    const {getFieldDecorator} = this.props.form;
    return (
      <Form layout="horizontal">
        <FormItem label="角色名称" {...formItemLayout}>
          {
            getFieldDecorator('role_name')(
              <Input type="text" placeholder="请输入角色名称"/>
            )
          }
        </FormItem>
        <FormItem label="状态" {...formItemLayout}>
          {
            getFieldDecorator('state')(
              <Select>
                <Option value={1}>开启</Option>
                <Option value={2}>关闭</Option>
              </Select>
            )
          }
        </FormItem>
      </Form>
    );
  }
}

RoleForm = Form.create({})(RoleForm);

2.3 设置权限

/permission/edit 权限设置接口

{
  "code": 0
}

Tree树形控件

文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能。

    1. import { Tree } from ‘antd’;
    2. 控件

TreeNode: 树的节点

import { Tree } from 'antd';

const { TreeNode } = Tree;

class Demo extends React.Component {
  onSelect = (selectedKeys, info) => {
    console.log('selected', selectedKeys, info);
  }

  onCheck = (checkedKeys, info) => {
    console.log('onCheck', checkedKeys, info);
  }

  render() {
    return (
      <Tree
        checkable
        defaultExpandedKeys={['0-0-0', '0-0-1']}
        defaultSelectedKeys={['0-0-0', '0-0-1']}
        defaultCheckedKeys={['0-0-0', '0-0-1']}
        onSelect={this.onSelect}
        onCheck={this.onCheck}
      >
        <TreeNode title="parent 1" key="0-0">
          <TreeNode title="parent 1-0" key="0-0-0" disabled>
            <TreeNode title="leaf" key="0-0-0-0" disableCheckbox />
            <TreeNode title="leaf" key="0-0-0-1" />
          </TreeNode>
          <TreeNode title="parent 1-1" key="0-0-1">
            <TreeNode title={<span style={{ color: '#1890ff' }}>sss</span>} key="0-0-1-0" />
          </TreeNode>
        </TreeNode>
      </Tree>
    );
  }
}

ReactDOM.render(<Demo />, mountNode);
  1. 加载完整权限列表

    • 方法一: 服务端返回完整的权限列表,前端加载
    • 方法二:前端定义完整的权限列表,服务端返回各自对应的权限,返回给前端
    • (本次采用本地定义权限列表的方式加载)
    • 采用递归的方式
  2. 根据用户各自的权限进行勾选

      <Tree
           checkable           使前面出现复选框,不加前面没有复选框   
           defaultExpandAll    默认全部展开
           onCheck             onCheck事件   点击复选框触发
    		
    	   checkedKeys 		   默认选中那些选项 	
            >
              <TreeNode title='平台权限' key="platform_all">
                {this.renderTreeNodes(menuConfig)}
              </TreeNode>
     </Tree>
    
  3. 将数据通过接口存入数据库

    handlePermEditSubmit = () => {
        // 获取表单的值 ,添加wrappedComponentRef属性
        let data = this.permForm.props.form.getFieldsValue();
        data.role_id = this.state.selectedItem.id; // 将角色id传回
        data.munus = this.state.menuInfo;   // 需要将menus数据  传到接口
    
        // 将数据传入接口
        axios.ajax({
          url: '/permission/edit',
          data: {
            params: {
              ...data
            }
          }
        }).then((res) => {
          if (res) {
            // 提交成功,   1. 关闭页面, 2. 重新请求数据
            this.setState({
              isPermVisible: false
            });
            this.requestList();  //刷新列表数据
          }
        });
      };
    

API Tree

Tree props
参数说明类型默认值
defaultExpandAll默认展开所有树节点booleanfalse
checkable节点前添加 Checkbox 复选框booleanfalse
checkedKeys(受控)选中复选框的树节点(注意:父子节点有关联,如果传入父节点key,则子节点自动选中;相应当子节点key都传入,父节点也自动选中。当设置checkablecheckStrictly,它是一个有checkedhalfChecked属性的对象,并且父子节点的选中与否不再关联string[] | {checked: string[], halfChecked: string[]}[]
onCheck点击复选框触发function(checkedKeys, e:{checked: bool, checkedNodes, node, event})-
TreeNode props
参数说明类型默认值
key被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意:整个树范围内的所有节点的 key 值不能重复!string内部计算出的节点位
title标题string|ReactNode‘—’
// src/pages/permission/index.js
import React from 'react';
import {Card, Button, Form, Modal, Input, Select, Tree} from 'antd';
import ETable from './../../components/ETable';
import Utils from './../../utils/utils';
import axios from './../../axios';
import menuConfig from './../../config/menuConfig';

const FormItem = Form.Item;
const Option = Select.Option;
const {TreeNode} = Tree;
// 或 const TreeNode = Tree.TreeNode

export default class PermissionUser extends React.Component {

  state = {
    isRoleVisible: false
  };

  componentWillMount() { // 通过生命周期函数加载接口
    axios.requestList(this, '/role/list', {}, true);
  }

  requestList = () => {
    axios.requestList(this, '/role/list', {}, true);
  };

  // 打开创建角色弹框
  handleRole = () => {...};

  // 角色提交
  handleRoleSubmit = () => {...};

  // 权限设置
  handlePermisson = () => {
    let item = this.state.selectedItem; //取出当前选中的项
    if (!item) {
      Modal.info({
        title: '温馨提示',
        content: '请选择一个角色'
      });
      return;
    }
    this.setState({
      isPermVisible: true,
      detailInfo: item,
      menuInfo: item.menus
    });
  };

  handlePermEditSubmit = () => {
    // 获取表单的值 ,添加wrappedComponentRef属性
    let data = this.permForm.props.form.getFieldsValue();
    data.role_id = this.state.selectedItem.id; // 将角色id传回
    data.munus = this.state.menuInfo;   // 需要将menus数据  传到接口

    // 将数据传入接口
    axios.ajax({
      url: '/permission/edit',
      data: {
        params: {
          ...data
        }
      }
    }).then((res) => {
      if (res) {
        // 提交成功,   1. 关闭页面, 2. 重新请求数据
        this.setState({
          isPermVisible: false
        });
        this.requestList();  //刷新列表数据
      }
    });
  };

  render() {
    const columns = [
      {
        title: '角色ID',
        dataIndex: 'id'
      }, {
        title: '角色名称',
        dataIndex: 'role_name'
      }, {
        title: '创建时间',
        dataIndex: 'create_time',
        render: Utils.formateDate
      }, {
        title: '使用状态',
        dataIndex: 'status',
        render(status) {
          return status == 1 ? '停用' : '启用';
        }
      }, {
        title: '授权时间',
        dataIndex: 'authorize_time',
        render: Utils.formateDate
      }, {
        title: '授权人',
        dataIndex: 'authorize_user_name'
      }
    ];
    return (
      <div>
        <Card>
          <Button type="primary" onClick={this.handleRole}>创建角色</Button>
          <Button type="primary" style={{marginLeft: 10, marginRight: 10}} onClick={this.handlePermisson}>设置权限</Button>
          <Button type="primary">用户授权</Button>
        </Card>
        <div className="content-wrap">
          <ETable
            dataSource={this.state.list}
            columns={columns}
            updateSelectedItem={Utils.updateSelectedItem.bind(this)}
            selectedRowKeys={this.state.selectedRowKeys}
            selectedItem={this.state.selectedItem}
          />
        </div>
        <Modal
          title="创建角色"
          visible={this.state.isRoleVisible}
          onOk={this.handleRoleSubmit}
          onCancel={() => {
            this.roleForm.props.form.resetFields(); // 表单重置
            this.setState({
              isRoleVisible: false,
            });
          }}
        >
          <RoleForm wrappedComponentRef={(inst) => {
            this.roleForm = inst;
          }}/>
        </Modal>
        <Modal
          title="设置权限"
          visible={this.state.isPermVisible}
          width={600}
          onOk={this.handlePermEditSubmit}
          onCancel={() => {
            this.setState({
              isPermVisible: false,
            });
          }}
        >
          <PermEditForm
            wrappedComponentRef={(inst) => {
              this.permForm = inst;
            }}
            detailInfo={this.state.detailInfo}
            menuInfo={this.state.menuInfo}
            patchMenuInfo={(checkedKeys) => {
              this.setState({
                menuInfo: checkedKeys
              });
            }}/>
        </Modal>
      </div>
    );
  }
}

// 子组件一-------角色绑定
class RoleForm extends React.Component {...}

RoleForm = Form.create({})(RoleForm);

// 子组件二---------设置权限
class PermEditForm extends React.Component {

  onCheck = (checkedKeys) => {
    // 将当前选中的项传回父组件  PermEditForm
    this.props.patchMenuInfo(checkedKeys);
  };

  // 递归渲染权限列表
  /**
   *
   * @param data:menuConfig.js 导入的权限列表
   */
  renderTreeNodes = (data) => {
    // 判断当前是否有子节点,如果有子节点children继续遍历,直到没有子节点为止
    return data.map((item) => {
      if (item.children) { // 判断当前是否有子节点
        return <TreeNode title={item.title} key={item.key}>
          {this.renderTreeNodes(item.children)}
        </TreeNode>;
      } else {
        return <TreeNode title={item.title} key={item.key}/>;
        // 也可写作
        // return <TreeNode {...item}/>
      }
    });
  };

  render() {
    const formItemLayout = {
      labelCol: {
        span: 5
      },
      wrapperCol: {
        span: 19
      }
    };
    const {getFieldDecorator} = this.props.form;
    const detail_info = this.props.detailInfo;
    const menu_info = this.props.menuInfo;
    console.log(detail_info);
    return (
      <Form layout="horizontal">
        <FormItem label='角色名称' {...formItemLayout}>
          <Input disabled placeholder={detail_info.role_name}/>
        </FormItem>
        <FormItem label='状态' {...formItemLayout}>
          {
            getFieldDecorator('status', {
              initialValue: (detail_info.status + 1) + ''
            })(
              <Select>
                <Option value='1'>启用</Option>
                <Option value='2'>停用</Option>
              </Select>
            )
          }
        </FormItem>
        <Tree
          checkable
          defaultExpandAll
          onCheck={(checkedKeys) => {
            // checkedKeys: 当前选中的节点
            this.onCheck(checkedKeys);
          }}
          checkedKeys={menu_info}
        >
          <TreeNode title='平台权限' key="platform_all">
            {this.renderTreeNodes(menuConfig)}
          </TreeNode>
        </Tree>
      </Form>
    );
  }
}

PermEditForm = Form.create({})(PermEditForm);

点击提交将数据带回数据接口:

2.4 完整代码

// src/pages/permission/index.js
import React from 'react';
import {Card, Button, Form, Modal, Input, Select, Tree} from 'antd';
import ETable from './../../components/ETable';
import Utils from './../../utils/utils';
import axios from './../../axios';
import menuConfig from './../../config/menuConfig';

const FormItem = Form.Item;
const Option = Select.Option;
const {TreeNode} = Tree;
// 或 const TreeNode = Tree.TreeNode

export default class PermissionUser extends React.Component {

  state = {
    isRoleVisible: false
  };

  componentWillMount() { // 通过生命周期函数加载接口
    axios.requestList(this, '/role/list', {}, true);
  }

  requestList = () => {
    axios.requestList(this, '/role/list', {}, true);
  };

  // 打开创建角色弹框
  handleRole = () => {
    this.setState({
      isRoleVisible: true,
    });
  };

  // 角色提交
  handleRoleSubmit = () => {
    const data = this.roleForm.props.form.getFieldsValue();
    console.log(data);
    axios.ajax({
      url: '/role/create', // //Easy Mock中只有{"code": 0}
      data: {
        params: data
      }
    }).then((res) => {
      if (res.code == 0) {
        this.setState({
          isRoleVisible: false   //关闭弹框
        });
        this.roleForm.props.form.resetFields();// 调用表单重置(清空表单数据)
        this.requestList();  //刷新列表数据
      }
    });
  };

  // 权限设置
  handlePermisson = () => {
    let item = this.state.selectedItem; //取出当前选中的项
    if (!item) {
      Modal.info({
        title: '温馨提示',
        content: '请选择一个角色'
      });
      return;
    }
    this.setState({
      isPermVisible: true,
      detailInfo: item,
      menuInfo: item.menus
    });
  };

  handlePermEditSubmit = () => {
    // 获取表单的值 ,添加wrappedComponentRef属性
    let data = this.permForm.props.form.getFieldsValue();
    data.role_id = this.state.selectedItem.id; // 将角色id传回
    data.munus = this.state.menuInfo;   // 需要将menus数据  传到接口

    // 将数据传入接口
    axios.ajax({
      url: '/permission/edit',
      data: {
        params: {
          ...data
        }
      }
    }).then((res) => {
      if (res) {
        // 提交成功,   1. 关闭页面, 2. 重新请求数据
        this.setState({
          isPermVisible: false
        });
        this.requestList();  //刷新列表数据
      }
    });
  };

  // 用户授权
  handleUserAuth = () => {
    let item = this.state.selectedItem;
    if (!item) {
      Modal.info({
        title: '温馨提示',
        content: '请选择一个角色'
      });
      return;
    }
    // 获取目标数据
    this.getRoleUserList(item.id)
  };

  // 获取用户角色列表
  getRoleUserList = (id) => {
    // id: 角色id , 获取角色id
    axios.ajax({
      url: '/role/user_list',
      data: {
        params: {
          id
        }
      }
    }).then((res) => {
      if (res) { //如何请求成功
        this.getAuthUserList(res.result);
      }
    });
  };

  // 筛选目标用户
  getAuthUserList = (dataSource) => {
    // 将数据(目标用户,全量用户)进行过滤的方法
    const mockData = [];
    const targetKeys = [];
    if (dataSource && dataSource.lenth > 0) {
      // 有数据
      for (let i = 0; i < dataSource.lenth; i++) {
        const data = {
          key: dataSource[i].user_id,
          title:dataSource[i].user_name,
          status:dataSource[i].status
        };
        
        if (data.status == 1) { // 如果status是1 说明是目标用户,加到targetKeys数组
          targetKeys.push(data)
        }
        // 否则 说明是全量数据, 加入全量数组列表
        mockData.push(data)
      }
    }
  };

  render() {
    const columns = [
      {
        title: '角色ID',
        dataIndex: 'id'
      }, {
        title: '角色名称',
        dataIndex: 'role_name'
      }, {
        title: '创建时间',
        dataIndex: 'create_time',
        render: Utils.formateDate
      }, {
        title: '使用状态',
        dataIndex: 'status',
        render(status) {
          return status == 1 ? '停用' : '启用';
        }
      }, {
        title: '授权时间',
        dataIndex: 'authorize_time',
        render: Utils.formateDate
      }, {
        title: '授权人',
        dataIndex: 'authorize_user_name'
      }
    ];
    return (
      <div>
        <Card>
          <Button type="primary" onClick={this.handleRole}>创建角色</Button>
          <Button type="primary" style={{marginLeft: 10, marginRight: 10}} onClick={this.handlePermisson}>设置权限</Button>
          <Button type="primary" onClick={this.handleUserAuth}>用户授权</Button>
        </Card>
        <div className="content-wrap">
          <ETable
            dataSource={this.state.list}
            columns={columns}
            updateSelectedItem={Utils.updateSelectedItem.bind(this)}
            selectedRowKeys={this.state.selectedRowKeys}
            selectedItem={this.state.selectedItem}
          />
        </div>
        <Modal
          title="创建角色"
          visible={this.state.isRoleVisible}
          onOk={this.handleRoleSubmit}
          onCancel={() => {
            this.roleForm.props.form.resetFields(); // 表单重置
            this.setState({
              isRoleVisible: false,
            });
          }}
        >
          <RoleForm wrappedComponentRef={(inst) => {
            this.roleForm = inst;
          }}/>
        </Modal>
        <Modal
          title="设置权限"
          visible={this.state.isPermVisible}
          width={600}
          onOk={this.handlePermEditSubmit}
          onCancel={() => {
            this.setState({
              isPermVisible: false,
            });
          }}
        >
          <PermEditForm
            wrappedComponentRef={(inst) => {
              this.permForm = inst;
            }}
            detailInfo={this.state.detailInfo}
            menuInfo={this.state.menuInfo}
            patchMenuInfo={(checkedKeys) => {
              this.setState({
                menuInfo: checkedKeys
              });
            }}/>
        </Modal>
      </div>
    );
  }
}

// 子组件一-------角色绑定
class RoleForm extends React.Component {
  render() {
    const formItemLayout = {
      labelCol: {
        span: 5
      },
      wrapperCol: {
        span: 19
      }
    };
    const {getFieldDecorator} = this.props.form;
    return (
      <Form layout="horizontal">
        <FormItem label="角色名称" {...formItemLayout}>
          {
            getFieldDecorator('role_name')(
              <Input type="text" placeholder="请输入角色名称"/>
            )
          }
        </FormItem>
        <FormItem label="状态" {...formItemLayout}>
          {
            getFieldDecorator('state')(
              <Select>
                <Option value={1}>开启</Option>
                <Option value={2}>关闭</Option>
              </Select>
            )
          }
        </FormItem>
      </Form>
    );
  }
}

RoleForm = Form.create({})(RoleForm);


// 子组件二---------设置权限
class PermEditForm extends React.Component {

  onCheck = (checkedKeys) => {
    // 将当前选中的项传回父组件  PermEditForm
    this.props.patchMenuInfo(checkedKeys);
  };

  // 递归渲染权限列表
  /**
   *
   * @param data:menuConfig.js 导入的权限列表
   */
  renderTreeNodes = (data) => {
    // 判断当前是否有子节点,如果有子节点children继续遍历,直到没有子节点为止
    return data.map((item) => {
      if (item.children) { // 判断当前是否有子节点
        return <TreeNode title={item.title} key={item.key}>
          {this.renderTreeNodes(item.children)}
        </TreeNode>;
      } else {
        return <TreeNode title={item.title} key={item.key}/>;
        // 也可写作
        // return <TreeNode {...item}/>
      }
    });
  };

  render() {
    const formItemLayout = {
      labelCol: {
        span: 5
      },
      wrapperCol: {
        span: 19
      }
    };
    const {getFieldDecorator} = this.props.form;
    const detail_info = this.props.detailInfo;
    const menu_info = this.props.menuInfo;
    // console.log(detail_info);
    return (
      <Form layout="horizontal">
        <FormItem label='角色名称' {...formItemLayout}>
          <Input disabled placeholder={detail_info.role_name}/>
        </FormItem>
        <FormItem label='状态' {...formItemLayout}>
          {
            getFieldDecorator('status', {
              initialValue: (detail_info.status + 1) + ''
            })(
              <Select>
                <Option value='1'>启用</Option>
                <Option value='2'>停用</Option>
              </Select>
            )
          }
        </FormItem>
        <Tree
          checkable
          defaultExpandAll
          onCheck={(checkedKeys) => {
            // checkedKeys: 当前选中的节点
            this.onCheck(checkedKeys);
          }}
          checkedKeys={menu_info}
        >
          <TreeNode title='平台权限' key="platform_all">
            {this.renderTreeNodes(menuConfig)}
          </TreeNode>
        </Tree>
      </Form>
    );
  }
}

PermEditForm = Form.create({})(PermEditForm);


点赞留言

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 好的,下面是SparkSQL代码笔记03——连接Hive的中文回复: 在SparkSQL中,我们可以通过以下步骤连接Hive: 1. 首先,需要在SparkSession中启用Hive支持,可以使用以下代码: ``` from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("SparkSQL Hive Example") \ .config("spark.sql.warehouse.dir", "/user/hive/warehouse") \ .enableHiveSupport() \ .getOrCreate() ``` 其中,`enableHiveSupport()`方法启用了Hive支持,`config("spark.sql.warehouse.dir", "/user/hive/warehouse")`指定了Hive元数据存储的目录。 2. 接下来,我们可以使用`spark.sql()`方法执行Hive SQL语句,例如: ``` spark.sql("show databases").show() ``` 这将显示所有的Hive数据库。 3. 如果需要在SparkSQL中访问Hive表,可以使用以下代码: ``` df = spark.sql("select * from my_hive_table") ``` 其中,`my_hive_table`是Hive中的表名。 4. 如果需要在SparkSQL中创建Hive表,可以使用以下代码: ``` spark.sql("create table my_hive_table (id int, name string)") ``` 这将在Hive中创建一个名为`my_hive_table`的表,包含两个列:`id`和`name`。 以上就是连接Hive的基本步骤。需要注意的是,连接Hive需要在Spark集群中安装Hive,并且需要将Hive的JAR包添加到Spark的CLASSPATH中。 ### 回答2: SparkSQL是Apache Spark的一个组件,它提供了用于分布式数据处理的高级SQL查询引擎。SparkSQL支持连接多种数据源,其中之一就是Hive。 如何连接Hive? 在开始连接Hive之前,我们需要确保Hadoop和Hive的配置已经被正确的设置好了,以便Spark能够访问Hive元数据和数据。 首先,我们需要在Spark环境中添加Hive支持。运行下面的代码: `from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("hive_support") \ .enableHiveSupport() \ .getOrCreate()` 其中,`.enableHiveSupport()`将启用hive支持。 接下来,我们可以使用SparkSession连接Hive。运行下面的代码: `hive_df = spark.sql("SELECT * FROM default.student")` 其中,“default”是Hive的默认数据库,“student”是Hive数据库中的表名。 如果你要访问非默认的Hive数据库,可以使用下面的代码: `hive_df = spark.sql("SELECT * FROM dbname.student")` 其中,“dbname”是非默认的Hive数据库名。 我们还可以使用HiveContext来连接Hive。运行下面的代码: `from pyspark.sql import HiveContext hive_context = HiveContext(sc)` 其中,“sc”是SparkContext对象。 我们可以像这样从Hive中检索数据: `hive_df = hive_ctx.sql("SELECT * FROM default.student")` 现在你已经成功地连接Hive并从中检索了数据,你可以使用SparkSQL的强大功能对数据进行分析。而在连接Hive之外,在SparkSQL中还可以连接其他数据源,包括MySQL、PostgreSQL、Oracle等。 ### 回答3: Spark SQL是一个强大的分布式计算引擎,它可以支持处理多种数据源,并可通过Spark SQL shell、Spark应用程序或JDBC/ODBC接口等方式进行操作。其中,连接Hive是Spark SQL最常用的数据源之一。下面,将介绍如何通过Spark SQL连接Hive。 1、在Spark配置中设置Hive Support 要连接Hive,首先需要在Spark配置中开启Hive Support。在启动Spark Shell时,可以添加如下参数: ``` ./bin/spark-shell --master local \ --conf spark.sql.warehouse.dir="/user/hive/warehouse" \ --conf spark.sql.catalogImplementation=hive \ --conf spark.sql.hive.metastore.version=0.13 \ --conf spark.sql.hive.metastore.jars=maven ``` 这里以本地模式为例,设置Spark SQL的元数据存储在本地文件系统中,设置Hive为catalog实现,以及为Hive Metastore设置版本和JAR文件路径。根据实际情况,还可以指定其他参数,如Hive Metastore地址、数据库名称、用户名和密码等。 2、创建SparkSession对象 在连接Hive之前,需要先创建SparkSession对象。可以通过调用SparkSession.builder()静态方法来构建SparkSession对象,如下所示: ``` val spark = SparkSession.builder() .appName("SparkSQLTest") .config("spark.sql.warehouse.dir", "/user/hive/warehouse") .enableHiveSupport() .getOrCreate() ``` 这里通过builder()方法指定应用程序名称、元数据存储路径以及启用Hive Support,最后调用getOrCreate()方法创建SparkSession对象。 3、通过Spark SQL操作Hive表 通过Spark SQL连接Hive后,就可以通过Spark SQL语句来操作Hive表了。例如,我们可以使用select语句查询Hive表中的数据: ``` val df = spark.sql("SELECT * FROM tablename") df.show() ``` 其中,select语句指定要查询的列和表名,然后通过show()方法来显示查询结果。 除了查询数据之外,Spark SQL还可以通过insertInto语句将数据插入到Hive表中: ``` val data = Seq(("Alice", 25), ("Bob", 30)) val rdd = spark.sparkContext.parallelize(data) val df = rdd.toDF("name", "age") df.write.mode(SaveMode.Append).insertInto("tablename") ``` 这里先创建一个包含数据的RDD对象,然后将其转换为DataFrame对象,并指定列名。接着,通过insertInto()方法将DataFrame对象中的数据插入到Hive表中。 总之,通过Spark SQL连接Hive可以方便地查询、插入、更新和删除Hive表中的数据,从而实现更加灵活和高效的数据处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值