持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
上一篇:React项目优化(2)-使用Axios+CommonModel统一处理Loading
按钮权限的概述
在系统中,需要根据不同的角色,分配不同的操作按钮。
在页面中,需要根据业务逻辑判断,按钮是否可以使用。
根据权限对按钮分类
| 分类 | 特点 | 核心 | 描述 |
|---|---|---|---|
| 第一类 | 受角色控制 | 存在与否 | 通过查询特定接口,返回配置信息,来决定按钮是否存在。 |
| 第二类 | 受业务逻辑控制 | 可用与否 | 根据具体的业务场景来决定具体按钮是否可用。比如:未启用的单据,才能点击"启用"操作 |
| 第三类 | 按钮总是可用 | 无限制 | 比如:刷新,查询,查看详情等。 |
我们约定: 第一类按钮通过是否渲染来控制,有则渲染,无则不渲染。第二类通过
disabled属性来控制是否可用。
按钮权限实现逻辑介绍
设置页面中按钮权限包括如下两个方面:
- 前端页面增加实现控制按钮权限的代码。
- 前端涉及
ButtonRoleGroup和GridButtonRole两个组件 ButtonRoleGroup组件需配置funcCode(组件根据此code请求,获取页面可以展示的按钮数据)GridButtonRole组件用于根据权限 控制表格操作列的按钮是否显示
- 前端涉及
- 使用管理员账号登陆系统, 在管理中心进行相关配置。
前端实践
1.首先导入组件
// 设置按钮区 按钮权限的组件
import ButtonRoleGroup from 'components/ButtonRoleGroup';
// 设置表格中 按钮权限的组件
import GridButtonRole from 'components/GridButtonRole';
- 设置我们页面对应的按钮权限编码
funcCode onComplete回调函数,将查询到的authData存放到modal中。 (表格GridButtonRole组件需要此值)Button按钮 加上props:role='add'根据按钮功能确定该值- 注意: 需要将
ButtonRoleGroup组件直接套在Button组件的外层 - 如有 启用/停用, 提交/收回等 需要在特殊处理: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>
不足之处
- 在
ButtonRoleGroup组件内部调用接口,查询数据。这就意味着,多次使用该组件,将多次调用接口。但是,接口数据入参相同,返回也相同。 - 组件封装不彻底:按钮权限数据获取后,需要在组件外通过回调函数处理。
解决思路
- 在
commonModel中进行请求数据的处理,在节点初始化页面中通过调用通用的getBtnAuthInfo方法获取按钮权限配置数据并放入CommonModel中。 - 在
ButtonRoleGroup组件中,增加判断逻辑,设置是否组件内初始化数据,如在外面初始化,直接传入authData数据即可。 这样做目的是兼容上一版本,组件内请求数据的方式。 - 删除
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
| 参数 | 类型 | 说明 | 是否必需 |
|---|---|---|---|
| url | string | 请求的权限接口地址 | 是, 有默认值,调用时不用写 |
| funcCode | string | 权限页面的编码,需要跟后端对接 | 是 |
| className | string | 样式 | 否 |
| onComplete | function | 按钮权限接口加载完毕后的回调 | 否 |
| onError | function | 按钮权限接口后端返回不是一个数组的错误回调 | 否 |
| innerInit | boolean | 是否内部发请求,初始化数据。如果在CommonModel请求了数据,可以设置为True | 否 |
GridButtonRole 组件API
| 参数 | 类型 | 说明 | 是否必需 |
|---|---|---|---|
| authData | array | 拥有权限的按钮标识数组 | 是 |
总结
- 封装组件的时候,一定要注意:坚持组件的单一职责原则。
- 需要判断到底有没有必要在组件内部请求数据。
- 组件内部能处理的逻辑尽量做到内部处理。
- 封装或调整组件,考虑如何兼容之前的逻辑。