React项目优化(3)-按钮权限组件优化

1,954 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

上一篇:React项目优化(2)-使用Axios+CommonModel统一处理Loading


按钮权限的概述

在系统中,需要根据不同的角色,分配不同的操作按钮。
在页面中,需要根据业务逻辑判断,按钮是否可以使用。

根据权限对按钮分类

分类特点核心描述
第一类受角色控制存在与否通过查询特定接口,返回配置信息,来决定按钮是否存在。
第二类受业务逻辑控制可用与否根据具体的业务场景来决定具体按钮是否可用。比如:未启用的单据,才能点击"启用"操作
第三类按钮总是可用无限制比如:刷新,查询,查看详情等。

我们约定: 第一类按钮通过是否渲染来控制,有则渲染,无则不渲染。第二类通过 disabled 属性来控制是否可用。

按钮权限实现逻辑介绍

设置页面中按钮权限包括如下两个方面:

  1. 前端页面增加实现控制按钮权限的代码。
    • 前端涉及ButtonRoleGroupGridButtonRole两个组件
    • ButtonRoleGroup 组件需配置 funcCode(组件根据此code请求,获取页面可以展示的按钮数据)
    • GridButtonRole 组件用于根据权限 控制表格操作列的按钮是否显示
  2. 使用管理员账号登陆系统, 在管理中心进行相关配置。

前端实践

1.首先导入组件

// 设置按钮区 按钮权限的组件
import ButtonRoleGroup from 'components/ButtonRoleGroup';
// 设置表格中 按钮权限的组件
import GridButtonRole from 'components/GridButtonRole'; 
  1. 设置我们页面对应的按钮权限编码funcCode
  2. onComplete 回调函数,将查询到的 authData 存放到modal中。 (表格GridButtonRole组件需要此值)
  3. Button按钮 加上props:role='add' 根据按钮功能确定该值
  4. 注意: 需要将ButtonRoleGroup组件直接套在Button组件的外层
  5. 如有 启用/停用, 提交/收回等 需要在特殊处理:role属性增加在外层div如下
<ButtonRoleGroup
     funcCode="FMS0203"
     onComplete={this.handleAuthArr}>
        <Button 
            iconType="uf uf-plus" 
            className="ml8"
            role="add"     //注意此项是必须
            onClick={() => {
                _this.onClickShowModel(0);
            }} > 
              新增
         </Button>
    {/* 启用 停用 特殊处理 在 按钮的 外层div 增加 role="enable" 属性 */}
    <div className="list-select-btn ml8" role="enable">
        <Button bordered onClick={() => this.onSelectEnable(1)}> 启用 </Button>   
    </div>
     //  ..... 其他按钮
</ButtonRoleGroup>
/**
* 处理 获取并设置按钮权限数组到modal的回调函数;
*/
handleAuthArr = (authData) =>{
    if(!!authData){
        actions.mainModel.updateState({
            authData:authData
        })
    }
}

// 处理表格操作列按钮,GridButtonRole 组件需要传递 authData(拥有的权限数组)

{
    title: "操作",
    width: 80,
    fixed: "right",
    dataIndex: "oper",
    key: "oper",
    render: (text, record, index) => {
        return (
            <GridButtonRole authData={authData}>
                <a className="operation-item"
                    role="edit"    //必须
                    href="javascript:;"
                    onClick={this.onClickAddEditView.bind(this, 1, record)}>
                        修改
                </a>
               {flag && <a className="operation-item"
                   role="delete"   //必须
                   href="javascript:;"
                   onClick={this.onClickAddEditView.bind(this, 1, record)}>
                       刪除
               </a>}
            </GridButtonRole>);
    }
};

详情页:import ButtonRoleGroup from 'components/ButtonRoleGroup;

<Header backFn={this.onBack} back title={titleArr[btnFlag]}>
    <div className="head-btn">
          {btnFlag !== 2 &&
            <ButtonRoleGroup funcCode="FMS0203">
              <Button colors="primary" role="save" className="ml8" onClick={this.onClickSave.bind(this, 1)}> 保存 </Button>
            </ButtonRoleGroup>
          }
          {btnFlag === 2 &&
            <ButtonRoleGroup funcCode="FMS0203">
              <Button shape="border" role="edit" className="ml8" onClick={this.toEditPage.bind(this)}> 修改 </Button>
            </ButtonRoleGroup>
          }
      </div>
</Header>

不足之处

  1. ButtonRoleGroup组件内部调用接口,查询数据。这就意味着,多次使用该组件,将多次调用接口。但是,接口数据入参相同,返回也相同。
  2. 组件封装不彻底:按钮权限数据获取后,需要在组件外通过回调函数处理。

解决思路

  1. commonModel 中进行请求数据的处理,在节点初始化页面中通过调用通用的getBtnAuthInfo 方法获取按钮权限配置数据并放入CommonModel中。
  2. ButtonRoleGroup组件中,增加判断逻辑,设置是否组件内初始化数据,如在外面初始化,直接传入authData 数据即可。 这样做目的是兼容上一版本,组件内请求数据的方式。
  3. 删除onComplete回调逻辑,直接重props中取配置数据即可。

代码示例

<ButtonRoleGroup innerInit={false} authData={authData}>
    // 各种按钮
<ButttonRoleGroup>
// 获取按钮权限数据接口
async getBtnAuthInfo(param) {
  let url = "/wbalone/security/auth";
  let option = {
    method: "get",
    param,
  };
  const resInfo = await request(url, option);
  let data = resInfo ? resInfo.data : {};
  if (Array.isArray(data)) {
    actions.commonModel.updateState({
      authData: data,
    });
  }
},

组件API

ButtonRoleGroup 组件 API

参数类型说明是否必需
urlstring请求的权限接口地址是, 有默认值,调用时不用写
funcCodestring权限页面的编码,需要跟后端对接
classNamestring样式
onCompletefunction按钮权限接口加载完毕后的回调
onErrorfunction按钮权限接口后端返回不是一个数组的错误回调
innerInitboolean是否内部发请求,初始化数据。如果在CommonModel请求了数据,可以设置为True

GridButtonRole 组件API

参数类型说明是否必需
authDataarray拥有权限的按钮标识数组

总结

  • 封装组件的时候,一定要注意:坚持组件的单一职责原则。
  • 需要判断到底有没有必要在组件内部请求数据。
  • 组件内部能处理的逻辑尽量做到内部处理。
  • 封装或调整组件,考虑如何兼容之前的逻辑。