<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端如何優(yōu)雅的設計管理端權限控制?

          共 46777字,需瀏覽 94分鐘

           ·

          2021-11-15 11:55

          大廠技術  高級前端  Node進階

          點擊上方 程序員成長指北,關注公眾號

          回復1,加入高級Node交流群

          后臺管理平臺內部權限大部分涉及到到兩種方式:資源權限  & 數(shù)據(jù)權限

          demo分支:https://github.com/rodchen-king/ant-design-pro-v2/tree/permission-branch

          1. 基本介紹

          • 資源權限:菜單導航欄 & 頁面 & 按鈕 資源可見權限。
          • 數(shù)據(jù)權限:對于頁面上的數(shù)據(jù)操作,同一個人同一個頁面相同的數(shù)據(jù)可能存在不同的數(shù)據(jù)操作權限。

          權限緯度

          • 角色維度:大部分的情況為:用戶 => 角色 => 權限
          • 用戶維度:用戶 => 權限

          表現(xiàn)形式

          • 基礎表現(xiàn)形式還是樹結構的展現(xiàn)形式,因為對應的菜單-頁面-按鈕是一個樹的從主干到節(jié)點的數(shù)據(jù)流向。

          2. 權限數(shù)據(jù)錄入與展示

          采用樹結構進行處理。唯一需要處理的是父子節(jié)點的聯(lián)動關系處理。這里因為不同的公司或者系統(tǒng)可能對于這部分的數(shù)據(jù)錄入方式不同,所以就不貼圖了。


          3. 權限數(shù)據(jù)控制

          3.1 用戶資源權限流程圖



          3.2 前端權限控制

          前端控制權限也是分為兩部分,菜單頁面 與 按鈕。因為前端權限控制的實現(xiàn),會因為后臺接口形式有所影響,但是大體方向是相同。還是會分為這兩塊內容。這里對于權限是使用多接口查詢權限,初始登錄查詢頁面權限,點擊業(yè)務頁面,查詢對應業(yè)務頁面的資源code。


          3.2.1 菜單權限

          菜單權限控制需要了解兩個概念:

          • 一個是可見的菜單頁面 :左側dom節(jié)點
          • 一個是可訪問的菜單頁面:系統(tǒng)當中路由這一塊

          這里說的意思是:我們所說的菜單權限控制,大多只是停留在菜單是否可見,但是系統(tǒng)路由的頁面可見和頁面上的菜單是否可見是兩回事情。假設系統(tǒng)路由/path1可見,盡管頁面上的沒有/path1對應的菜單顯示。我們直接在瀏覽器輸入對應的path1,還是可以訪問到對應的頁面。這是因為系統(tǒng)路由那一塊其實我們是沒有去處理的。

          了解了這個之后,我們需要做菜單頁面權限的時候就需要去考慮兩塊,并且是對應的。


          3.2.1.1 路由權限

          代碼地址: https://github.com/rodchen-king/ant-design-pro-v2/commit/0e7895c56e4962d75ab8ccf4637cefca3f5f71b6#diff-a7acc04e8fb20252554c588f7b7a8564

          這里是有兩種做法:第一種,控制路由的配置,當然不是路由配置文件里去配置。而是生效的路由配置里去做。第二種,完全不做這里的路由控制,而是在路由跳轉到沒有權限的頁面,寫邏輯校驗是否有當前的權限,然后手動跳轉到403頁面。

          這里還是先用第一種做法來做:因為這里用第一種做了之后,菜單可見權限自動適配好了。會省去我們很多事情。


          a. 路由文件,定義菜單頁面權限。并且將exception以及404的路由添加notInAut標志,這個標志說明:這兩個路由不走權限校驗。同理的還有 /user。

          export default [
            // user
            {
              path'/user',
              component'../layouts/UserLayout',
              routes: [
                { path'/user'redirect'/user/login' },
                { path'/user/login'component'./User/Login' },
                { path'/user/register'component'./User/Register' },
                { path'/user/register-result'component'./User/RegisterResult' },
              ],
            },
            // app
            {
              path'/',
              component'../layouts/BasicLayout',
              Routes: ['src/pages/Authorized'],
              authority: ['admin''user'],
              routes: [
                // dashboard
                { path'/'redirect'/list/table-list' },
                // forms
                {
                  path'/form',
                  icon'form',
                  name'form',
                  code'form_menu',
                  routes: [
                    {
                      path'/form/basic-form',
                      code'form_basicForm_page',
                      name'basicform',
                      component'./Forms/BasicForm',
                    },
                  ],
                },
                // list
                {
                  path'/list',
                  icon'table',
                  name'list',
                  code'list_menu',
                  routes: [
                    {
                      path'/list/table-list',
                      name'searchtable',
                      code'list_tableList_page',
                      component'./List/TableList',
                    },
                  ],
                },
                {
                  path'/profile',
                  name'profile',
                  icon'profile',
                  code'profile_menu',
                  routes: [
                    // profile
                    {
                      path'/profile/basic',
                      name'basic',
                      code'profile_basic_page',
                      component'./Profile/BasicProfile',
                    },
                    {
                      path'/profile/advanced',
                      name'advanced',
                      code'profile_advanced_page',
                      authority: ['admin'],
                      component'./Profile/AdvancedProfile',
                    },
                  ],
                },
                {
                  name'exception',
                  icon'warning',
                  notInAuttrue,
                  hideInMenutrue,
                  path'/exception',
                  routes: [
                    // exception
                    {
                      path'/exception/403',
                      name'not-permission',
                      component'./Exception/403',
                    },
                    {
                      path'/exception/404',
                      name'not-find',
                      component'./Exception/404',
                    },
                    {
                      path'/exception/500',
                      name'server-error',
                      component'./Exception/500',
                    },
                    {
                      path'/exception/trigger',
                      name'trigger',
                      hideInMenutrue,
                      component'./Exception/TriggerException',
                    },
                  ],
                },
                {
                  notInAuttrue,
                  component'404',
                },
              ],
            },
          ];


          b. 修改app.js 文件,加載路由

          export const dva = {
            config: {
              onError(err) {
                err.preventDefault();
              },
            },
          };

          let authRoutes = null;

          function ergodicRoutes(routes, authKey, authority{
            routes.forEach(element => {
              if (element.path === authKey) {
                Object.assign(element.authority, authority || []);
              } else if (element.routes) {
                ergodicRoutes(element.routes, authKey, authority);
              }
              return element;
            });
          }

          function customerErgodicRoutes(routes{
            const menuAutArray = (localStorage.getItem('routerAutArray') || '').split(',');

            routes.forEach(element => {
              // 沒有path的情況下不需要走邏輯檢查
              // path 為 /user 不需要走邏輯檢查
              if (element.path === '/user' || !element.path) {
                return element;
              }

              // notInAut 為true的情況下不需要走邏輯檢查
              if (!element.notInAut) {
                if (menuAutArray.indexOf(element.code) >= 0 || element.path === '/') {
                  if (element.routes) {
                    // eslint-disable-next-line no-param-reassign
                    element.routes = customerErgodicRoutes(element.routes);

                    // eslint-disable-next-line no-param-reassign
                    element.routes = element.routes.filter(item => !item.isNeedDelete);
                  }
                } else {
                  // eslint-disable-next-line no-param-reassign
                  element.isNeedDelete = true;
                }
              }

              /**
               * 后臺接口返回子節(jié)點的情況,父節(jié)點需要溯源處理
               */

              // notInAut 為true的情況下不需要走邏輯檢查
              // if (!element.notInAut) {
              //   if (element.routes) {
              //     // eslint-disable-next-line no-param-reassign
              //     element.routes = customerErgodicRoutes(element.routes);

              //     // eslint-disable-next-line no-param-reassign
              //     if (element.routes.filter(item => item.isNeedSave && !item.hideInMenu).length) {
              //       // eslint-disable-next-line no-param-reassign
              //       element.routes = element.routes.filter(item => item.isNeedSave);
              //       if (element.routes.length) {
              //         // eslint-disable-next-line no-param-reassign
              //         element.isNeedSave = true;
              //       }
              //     }
              //   } else if (menuAutArray.indexOf(element.code) >= 0) {
              //     // eslint-disable-next-line no-param-reassign
              //     element.isNeedSave = true;
              //   }
              // } else {
              //   // eslint-disable-next-line no-param-reassign
              //   element.isNeedSave = true;
              // }

              return element;
            });

            return routes;
          }

          export function patchRoutes(routes{
            Object.keys(authRoutes).map(authKey =>
              ergodicRoutes(routes, authKey, authRoutes[authKey].authority),
            );

            customerErgodicRoutes(routes);

            /**
             * 后臺接口返回子節(jié)點的情況,父節(jié)點需要溯源處理
             */

            window.g_routes = routes.filter(item => !item.isNeedDelete);

            /**
             * 后臺接口返回子節(jié)點的情況,父節(jié)點需要溯源處理
             */

            // window.g_routes = routes.filter(item => item.isNeedSave);
          }

          export function render(oldRender{
            authRoutes = '';
            oldRender();
          }


          c. 修改login.js,獲取路由當中的code便利獲取到,進行查詢權限

          import { routerRedux } from 'dva/router';
          import { stringify } from 'qs';
          import { fakeAccountLogin, getFakeCaptcha } from '@/services/api';
          import { getAuthorityMenu } from '@/services/authority';
          import { setAuthority } from '@/utils/authority';
          import { getPageQuery } from '@/utils/utils';
          import { reloadAuthorized } from '@/utils/Authorized';
          import routes from '../../config/router.config';

          export default {
            namespace'login',

            state: {
              statusundefined,
            },

            effects: {
              *login({ payload }, { call, put }) {
                const response = yield call(fakeAccountLogin, payload);
                yield put({
                  type'changeLoginStatus',
                  payload: response,
                });
                // Login successfully
                if (response.status === 'ok') {
                  // 這里的數(shù)據(jù)通過接口返回菜單頁面的權限是什么

                  const codeArray = [];
                  // eslint-disable-next-line no-inner-declarations
                  function ergodicRoutes(routesParam{
                    routesParam.forEach(element => {
                      if (element.code) {
                        codeArray.push(element.code);
                      }
                      if (element.routes) {
                        ergodicRoutes(element.routes);
                      }
                    });
                  }

                  ergodicRoutes(routes);
                  const authMenuArray = yield call(getAuthorityMenu, codeArray.join(','));
                  localStorage.setItem('routerAutArray', authMenuArray.join(','));

                  reloadAuthorized();
                  const urlParams = new URL(window.location.href);
                  const params = getPageQuery();
                  let { redirect } = params;
                  if (redirect) {
                    const redirectUrlParams = new URL(redirect);
                    if (redirectUrlParams.origin === urlParams.origin) {
                      redirect = redirect.substr(urlParams.origin.length);
                      if (redirect.match(/^\/.*#/)) {
                        redirect = redirect.substr(redirect.indexOf('#') + 1);
                      }
                    } else {
                      window.location.href = redirect;
                      return;
                    }
                  }
                  // yield put(routerRedux.replace(redirect || '/'));

                  // 這里之所以用頁面跳轉,因為路由的重新設置需要頁面重新刷新才可以生效
                  window.location.href = redirect || '/';
                }
              },

              *getCaptcha({ payload }, { call }) {
                yield call(getFakeCaptcha, payload);
              },

              *logout(_, { put }) {
                yield put({
                  type'changeLoginStatus',
                  payload: {
                    statusfalse,
                    currentAuthority'guest',
                  },
                });
                reloadAuthorized();
                yield put(
                  routerRedux.push({
                    pathname'/user/login',
                    search: stringify({
                      redirectwindow.location.href,
                    }),
                  }),
                );
              },
            },

            reducers: {
              changeLoginStatus(state, { payload }) {
                setAuthority(payload.currentAuthority);
                return {
                  ...state,
                  status: payload.status,
                  type: payload.type,
                };
              },
            },
          };


          d. 添加service

          import request from '@/utils/request';

          // 查詢菜單權限
          export async function getAuthorityMenu(codes{
            return request(`/api/authority/menu?resCodes=${codes}`);
          }

          // 查詢頁面按鈕權限
          export async function getAuthority(params{
            return request(`/api/authority?codes=${params}`);
          }



          3.2.1.2 菜單可見權限

          參照上面的方式,這里的菜單可見權限不用做其他的操作。

          3.2.2 按鈕權限

          代碼地址: https://github.com/rodchen-king/ant-design-pro-v2/commit/0e7895c56e4962d75ab8ccf4637cefca3f5f71b6#diff-a7acc04e8fb20252554c588f7b7a8564

          按鈕權限上就涉及到兩塊,資源權限數(shù)據(jù)權限。數(shù)據(jù)獲取的方式不同,代碼邏輯上會稍微有點不同。核心是業(yè)務組件內部的code,在加載的時候就自行累加,然后在頁面加載完成的時候,發(fā)送請求。拿到數(shù)據(jù)之后,自行進行權限校驗。盡量減少業(yè)務頁面代碼的復雜度。


          資源權限邏輯介紹:

          1. PageHeaderWrapper包含的業(yè)務頁面存在按鈕權限
          2. 按鈕權限通過AuthorizedButton包含處理,需要添加code。但是業(yè)務頁面因為是單獨頁面發(fā)送當前頁面code集合去查詢權限code,然后在AuthorizedButton進行權限邏輯判斷。
          3. 所以AuthorizedButtoncomponentWillMount生命周期進行當前業(yè)務頁面的code累加。累加完成之后,通過PageHeaderWrappercomponentDidMount生命周期函數(shù)發(fā)送權限請求,拿到權限code,通過公有globalAuthority model讀取數(shù)據(jù)進行權限邏輯判斷。
          4. 對于業(yè)務頁面的調用參考readme進行使用。因為對于彈出框內部的code,在業(yè)務列表頁面渲染的時候,組件還未加載,所以通過extencode提前將code累加起來進行查詢權限。

          數(shù)據(jù)權限介紹:

          1. 涉及數(shù)據(jù)權限,則直接將對應的數(shù)據(jù)規(guī)則放進AuthorizedButton內部進行判斷,需要傳入的數(shù)據(jù)則直接通過props傳入即可。因為數(shù)據(jù)權限的規(guī)則不同,這里就沒有舉例子。
          2. 需要注意的邏輯是資源權限和數(shù)據(jù)權限是串行的,先判斷資源權限,然后判斷數(shù)據(jù)權限。

          a. 添加公用authority model

          /* eslint-disable no-unused-vars */
          /* eslint-disable no-prototype-builtins */
          import { getAuthority } from '@/services/authority';

          export default {
            namespace'globalAuthority',

            state: {
              hasAuthorityCodeArray: [], // 獲取當前具有權限的資源code
              pageCodeArray: [], // 用來存儲當前頁面存在的資源code
            },

            effects: {
              /**
               * 獲取當前頁面的權限控制
               */

              *getAuthorityForPage({ payload }, { put, call, select }) {
                // 這里的資源code都是自己加載的
                const pageCodeArray = yield select(state => state.globalAuthority.pageCodeArray);
                const response = yield call(getAuthority, pageCodeArray);

                if (pageCodeArray.length) {
                  yield put({
                    type'save',
                    payload: {
                      hasAuthorityCodeArray: response,
                    },
                  });
                }
              },

              *plusCode({ payload }, { put, select }) {
                // 組件累加當前頁面的code,用來發(fā)送請求返回對應的權限code
                const { codeArray = [] } = payload;
                const pageCodeArray = yield select(state => state.globalAuthority.pageCodeArray);

                yield put({
                  type'save',
                  payload: {
                    pageCodeArray: pageCodeArray.concat(codeArray),
                  },
                });
              },

              // eslint-disable-next-line no-unused-vars
              *resetAuthorityForPage({ payload }, { put, call }) {
                yield put({
                  type'save',
                  payload: {
                    hasAuthorityCodeArray: [],
                    pageCodeArray: [],
                  },
                });
              },
            },

            reducers: {
              save(state, { payload }) {
                return {
                  ...state,
                  ...payload,
                };
              },
            },
          };


          b. 修改PageHeaderWrapper文件【因為所有的業(yè)務頁面都是這個組件的子節(jié)點】

          import React, { PureComponent } from 'react';
          import { FormattedMessage } from 'umi/locale';
          import Link from 'umi/link';
          import PageHeader from '@/components/PageHeader';
          import { connect } from 'dva';
          import MenuContext from '@/layouts/MenuContext';
          import { Spin } from 'antd';
          import GridContent from './GridContent';
          import styles from './index.less';

          class PageHeaderWrapper extends PureComponent {
            componentDidMount() {
              const { dispatch } = this.props;
              dispatch({
                type'globalAuthority/getAuthorityForPage'// 發(fā)送請求獲取當前頁面的權限code
              });
            }

            componentWillUnmount() {
              const { dispatch } = this.props;
              dispatch({
                type'globalAuthority/resetAuthorityForPage',
              });
            }

            render() {
              const { children, contentWidth, wrapperClassName, top, loading, ...restProps } = this.props;

              return (
                <Spin spinning={loading}>
                  <div style={{ margin: '-24px -24px 0' }} className={wrapperClassName}>
                    {top}
                    <MenuContext.Consumer>
                      {value => (
                        <PageHeader
                          wide={contentWidth === 'Fixed'}
                          home={<FormattedMessage id="menu.home" defaultMessage="Home" />
          }
                          {...value}
                          key="pageheader"
                          {...restProps}
                          linkElement={Link}
                          itemRender={item => {
                            if (item.locale) {
                              return <FormattedMessage id={item.locale} defaultMessage={item.title} />;
                            }
                            return item.title;
                          }}
                        />
                      )}
                    </MenuContext.Consumer>
                    {children ? (
                      <div className={styles.content}>
                        <GridContent>{children}</GridContent>
                      </div>
                    ) : null}
                  </div>
                </Spin>

              );
            }
          }

          export default connect(({ setting, globalAuthority, loading }) => ({
            contentWidth: setting.contentWidth,
            globalAuthority,
            loading: loading.models.globalAuthority,
          }))(PageHeaderWrapper);


          c. 添加AuthorizedButton公共組件

          import React, { Component } from 'react';
          import PropTypes from 'prop-types';
          import { connect } from 'dva';

          @connect(({ globalAuthority }) => ({
            globalAuthority,
          }))
          class AuthorizedButton extends Component {
            static contextTypes = {
              isMobile: PropTypes.bool,
            };

            componentWillMount() {
              // extendcode 擴展表格中的code還沒有出現(xiàn)的情況
              const {
                dispatch,
                code,
                extendCode = [],
                globalAuthority: { pageCodeArray },
              } = this.props;

              let codeArray = [];

              if (code) {
                codeArray.push(code);
              }

              if (extendCode && extendCode.length) {
                codeArray = codeArray.concat(extendCode);
              }

              // code已經存在,證明是頁面數(shù)據(jù)渲染之后或者彈出框的按鈕資源,不需要走dva了
              if (pageCodeArray.indexOf(code) >= 0) {
                return;
              }

              dispatch({
                type'globalAuthority/plusCode',
                payload: {
                  codeArray,
                },
              });
            }

            checkAuthority = code => {
              const {
                globalAuthority: { hasAuthorityCodeArray },
              } = this.props;

              return hasAuthorityCodeArray.indexOf(code) >= 0// 資源權限
            };

            render() {
              const { children, code } = this.props;

              return (
                <span style={{ display: this.checkAuthority(code) ? 'inline' : 'none' }}>{children}</span>
              );
            }
          }

          export default AuthorizedButton;


          d. 添加AuthorizedButton readme文件

          https://github.com/rodchen-king/ant-design-pro-v2/blob/permission-branch/src/components/AuthorizedButton/index.md

          3.2.3 按鈕權限擴展-鏈接權限控制

          代碼地址: https://github.com/rodchen-king/ant-design-pro-v2/commit/02914330f17f11f3d6e8b7d5c1239702c6832337

          背景:頁面上有需要控制跳轉鏈接的權限,有權限則可以跳轉,沒有權限則不能跳轉。


          a.公共model添加新的state:codeAuthorityObject

          通過redux-devtool,查看到codeAuthorityObject的狀態(tài)值為:key:code值,value的值為true/false。true代表,有權限,false代表無權限。主要用于開發(fā)人員自己做相關處理。


          b.需要控制的按鈕code,通過其他方式擴展進行code計算,發(fā)送請求獲取權限


          c.獲取數(shù)據(jù)進行數(shù)據(jù)控制



          3.2.4 按鈕數(shù)據(jù)權限

          代碼地址:https://github.com/rodchen-king/ant-design-pro-v2/commit/463514b0964c4c0187a503d315aa9f088e963f71

          背景

          數(shù)據(jù)權限是對于業(yè)務組件內部表格組件的數(shù)據(jù)進行的數(shù)據(jù)操作權限。列表數(shù)據(jù)可能歸屬于不同的數(shù)據(jù)類型,所以具有不同的數(shù)據(jù)操作權限。對于批量操作則需要判斷選擇的數(shù)據(jù)是否都具有操作權限,然后顯示是否可以批量操作,如果有一個沒有操作權限,都不能進行操作。


          總體思路

          場景:比如在商品列表中,每條商品記錄后面的“操作”一欄下用三個按鈕:【編輯】、【上架/下架】、【刪除】,而對于某一個用戶,他可以查看所有的商品,但對于某些品牌他可以【上架/下架】但不能【編輯】,則前端需要控制到每一個商品后面的按鈕的可用狀態(tài),比如用戶A對于某一條業(yè)務數(shù)據(jù)(id=1999)有編輯權限,則這條記錄上的【編輯】按鈕對他來說是可見的(前提是他首先要有【編輯】這個按鈕的資源權限),但對于另一條記錄(id=1899)是沒有【編輯】權限,則這條記錄上的【編輯】按鈕對他來說是不可見的。


          按鈕【actType】屬性定義

          每個數(shù)據(jù)操作的按鈕上加一個屬性 “actType”代表這個按鈕的動作類型(如:編輯、刪除、審核等),這個屬性是資源權限的接口返回的,前端在調這個接口時將這個屬性記錄下來,或者保存到對應的控件中。所以前端可以不用關于這個屬性的每個枚舉值代表的是什么含義,只需根據(jù)接口的返回值賦值就好。用興趣的同學也可以參考一下actType取值如下:1 可讀,2 編輯,3 可讀+可寫, 4 可收貨,8 可發(fā)貨,16 可配貨, 32 可審核,64 可完結


          業(yè)務接口返回權限類型字段【permissionType】

          對于有權限控制的業(yè)務數(shù)據(jù),列表接口或者詳情接口都會返回一個“permissionType”的字段,這個字段代表當前用戶對于這條業(yè)務數(shù)據(jù)的權限類型,如當 permissionType=2 代表這個用戶對于這條數(shù)據(jù)有【編輯權限】,permisionType=4 代表這個用戶對于這條業(yè)務數(shù)據(jù)有收貨的權限,permisionType=6表示這個用戶對于這條記錄用編輯和發(fā)貨的權限(6=2+4)


          怎么控制按鈕的可用狀態(tài)?

          現(xiàn)在列表上有三個按鈕,【編輯】、【收貨】、【完結】,它們對應的“actType”分別為2、4、64,某一條數(shù)據(jù)的permissionType=3,這時這三個按鈕的狀態(tài)怎么判斷呢,permissionType=3 我們可以分解為 1+2,表示這個用戶對于這條記錄有“可讀”+“編輯”權限,則這三個按鈕中,只有【編輯】按鈕是可用的。那么判斷的公式為:

          ((data[i].permissionType & obj.actType)==obj.actType)

          前端的js數(shù)據(jù)進行&判斷

          需要進行數(shù)據(jù)轉換 data.toString(2): 將數(shù)據(jù)進行2進制轉換成二進制字符串。parseInt(permissionType,2) : 二進制字符串轉換成二進制數(shù)據(jù)。


          代碼修改

          接口mock返回數(shù)據(jù)

          response = [{
                "type"3,
                "name""創(chuàng)建活動-10001",
                "actType"0,
                "code""10001"
              }, {
                "type"3,
                "name""編輯-10002",
                "actType"2,
                "code""10002"
              }, {
                "type"3,
                "name""配置-10005",
                "actType"4,
                "code""10005"
              }, {
                "type"3,
                "name""訂閱警報-10006",
                "actType"8,
                "code""10006"
              }, {
                "type"3,
                "name""查詢詳情-20001",
                "actType"16,
                "code""20001"
              }, {
                "type"3,
                "name""批量操作-10007",
                "actType"32,
                "code""10007"
              }, {
                "type"3,
                "name""更多操作-10008",
                "actType"64,
                "code""10008"
              }]

          每一個返回的接口權限會將對應的actType一起返回。

          getAuthorityForPage代碼修改簡單修改一下,因為之前返回的是code數(shù)組,現(xiàn)在返回的是對象


             /**
               * 獲取當前頁面的權限控制
               */

              *getAuthorityForPage({ payload }, { put, call, select }) {
                // 這里的資源code都是自己加載的
                const pageCodeArray = yield select(state => state.globalAuthority.pageCodeArray);
                const response = yield call(getAuthority, pageCodeArray);
                const hasAuthorityCodeArray = response || [];
                const codeAuthorityObject = {};

                pageCodeArray.forEach((value, index, array) => {
                  codeAuthorityObject[value] = hasAuthorityCodeArray.map(item => item.code).indexOf(value) >= 0;
                });

                // debugger
                yield put({
                  type'save',
                  payload: {
                    hasAuthorityCodeArray,
                    codeAuthorityObject,
                  },
                });
              },

          修改AuthorizedButton代碼

          增加數(shù)據(jù)權限判斷

          /* eslint-disable eqeqeq */
          import React, { Component } from 'react';
          import PropTypes from 'prop-types';
          import { connect } from 'dva';

          @connect(({ globalAuthority }) => ({
            globalAuthority,
          }))
          class AuthorizedButton extends Component {
            static contextTypes = {
              isMobile: PropTypes.bool,
            };

            componentWillMount() {
              // extendcode 擴展表格中的code還沒有出現(xiàn)的情況
              const {
                dispatch,
                code,
                extendCode = [],
                globalAuthority: { pageCodeArray },
              } = this.props;

              let codeArray = [];

              if (code) {
                codeArray.push(code);
              }

              if (extendCode && extendCode.length) {
                codeArray = codeArray.concat(extendCode);
              }

              // code已經存在,證明是頁面數(shù)據(jù)渲染之后或者彈出框的按鈕資源,不需要走dva了
              if (pageCodeArray.indexOf(code) >= 0) {
                return;
              }

              dispatch({
                type'globalAuthority/plusCode',
                payload: {
                  codeArray,
                },
              });
            }

            checkAuthority = code => {
              const {
                globalAuthority: { hasAuthorityCodeArray },
              } = this.props;

              return hasAuthorityCodeArray.map(item => item.code).indexOf(code) >= 0 && this.checkDataAuthority(); // 資源權限
            };


            /**
             * 檢測數(shù)據(jù)權限
             */

            checkDataAuthority = () => {
              const {
                globalAuthority: { hasAuthorityCodeArray },
                code,                                         // 當前按鈕的code
                actType,                                      // 當前按鈕的actType的值通過傳遞傳入
                recordPermissionType,                         // 單條數(shù)據(jù)的數(shù)據(jù)操作權限總和
                actTypeArray
              } = this.props;

              if (recordPermissionType || actTypeArray) {     // 單條數(shù)據(jù)權限校驗
                const tempCode = hasAuthorityCodeArray.filter(item => item.code === code)
                let tempActType = ''

                if (actType) {
                  tempActType = actType
                } else if (tempCode.length) {
                  tempActType = tempCode[0].actType
                } else {
                  return true;                                // 默認返回true
                }

                if (actTypeArray) {                           // 批量操作
                  return !actTypeArray.some(item => !this.checkPermissionType(item.toString(2), tempActType.toString(2)))
                }

                // 單條數(shù)據(jù)操作
                return this.checkPermissionType(recordPermissionType.toString(2), tempActType.toString(2))
              } 

              return true;                                    // 如果字段沒有值的情況下,證明不需要進行數(shù)據(jù)權限
            }

            /**
             * 二進制檢查當前當前數(shù)據(jù)是否具有當前權限
             * @param {*} permissionType 
             * @param {*} actType
             */

            checkPermissionType = (permissionType, actType) => 
              // eslint-disable-next-line no-bitwise
               (parseInt(permissionType,2) & parseInt(actType,2)).toString(2) == actType
            

            render() {
              const { children, code } = this.props;

              return (
                <span style={{ display: this.checkAuthority(code) ? 'inline' : 'none' }}>{children}</span>
              );
            }
          }

          export default AuthorizedButton;


          調用方式

          單條數(shù)據(jù)操作

          <AuthoriedButton code="10005" recordPermissionType={record.permissionType}>
            <a onClick={() => this.handleUpdateModalVisible(true, record)}>配置</a>
          </AuthoriedButton>

          批量操作

           <AuthoriedButton code="10007" actTypeArray={getNotDuplicateArrayById(selectedRows, 'permissionType')}>
               <Button>批量操作</Button>
           </AuthoriedButton>

          代碼地址:https://github.com/rodchen-king/ant-design-pro-v2/commit/463514b0964c4c0187a503d315aa9f088e963f71

          Node 社群


          我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學習感興趣的話(后續(xù)有計劃也可以),我們可以一起進行Node.js相關的交流、學習、共建。下方加 考拉 好友回復「Node」即可。


             “分享、點贊在看” 支持一波??


          瀏覽 48
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费国产黄色电影 | 男人天堂2025手机版 | 欧美黄色成人 | 国产探花视频在线播放 | 夜夜躁狠狠躁日日躁视频 |