Skip to content

Commit

Permalink
Merge pull request #139 from ts-react/v1
Browse files Browse the repository at this point in the history
V1
  • Loading branch information
wangxingkang authored Jun 1, 2019
2 parents cd84f34 + 3b1663a commit 0d76dfd
Show file tree
Hide file tree
Showing 14 changed files with 110 additions and 69 deletions.
3 changes: 2 additions & 1 deletion config/router.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ export default [
name: 'exception',
icon: 'warning',
path: '/exception',
authority: '*',
hideInMenu: true,
routes: [
// exception
Expand Down Expand Up @@ -105,11 +104,13 @@ export default [
{
path: '/system/user',
name: 'user',
authority: ['system/action1'],
component: './system/users'
},
{
path: '/system/group',
name: 'group',
authority: ['system/action2'],
component: './system/groups'
}
],
Expand Down
36 changes: 36 additions & 0 deletions src/components/authorized/check-authority.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import isArray from 'lodash/isArray';
import isString from 'lodash/isString';
import Policy from '@jiumao/policy';

export type TAuthority = string[] | string;

/**
* 权限检查方法
* @param { 权限判定 | Permission judgment } authority
* @param { 权限验证方法 | no pass components } policy
*/
const checkAuthority = (
policy?: Policy,
authority?: TAuthority
): boolean => {
let result = true;

// 数组处理
if (isArray(authority)) {
if (!policy.multipleVerify(authority)) {
result = false;
}
}

// string 处理
if (isString(authority)) {
if (!policy.combinationVerify(authority)) {
result = false;
}
}

return result;
};

export default checkAuthority;
4 changes: 2 additions & 2 deletions src/components/sidebar-menu/sidebar-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import classNames from 'classnames';
import PageLoading from '@/components/page-loading';
import { APP_DEFAULT_CONFIG } from '@/config';
import defaultSettings from '@/config/default-settings';
import BaseMenu, { IBaseMenuProps } from './base-menu';
import { getDefaultCollapsedSubMenus } from './utils';
import './sidebar-menu.less';
Expand All @@ -12,7 +12,7 @@ export interface ISidebarMenuProps extends IBaseMenuProps {
isMobile?: boolean;
}

const { title } = APP_DEFAULT_CONFIG;
const { title } = defaultSettings;

const SidebarMenu: React.FC<ISidebarMenuProps> = (props) => {
const { prefixCls, className, style, collapsed, logo } = props;
Expand Down
5 changes: 4 additions & 1 deletion src/config/default-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export interface IDefaultSettings {
iconFontUrl: string;
// 项目标题
title: string;
// 公司名称
company: string;
}

const defaultSettings: IDefaultSettings = {
Expand All @@ -23,7 +25,8 @@ const defaultSettings: IDefaultSettings = {
},
fixedHeader: false,
title: 'React Admin Template',
iconFontUrl: ''
iconFontUrl: '',
company: '九毛科技',
};

export default defaultSettings;
6 changes: 2 additions & 4 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// axios 相关配置
export const AXIOS_DEFAULT_CONFIG = {
// ajax 相关配置
export const AJAX_DEFAULT_CONFIG = {
timeout: 20000,
withCredentials: true,
// 使用webpack DefinePlugin 插件
Expand All @@ -10,8 +10,6 @@ export const AXIOS_DEFAULT_CONFIG = {

// 项目相关配置
export const APP_DEFAULT_CONFIG = {
companyName: '九毛科技',
title: 'React Admin Template',
// 免登陆白名单
whiteList: ['/user/*']
};
Expand Down
14 changes: 7 additions & 7 deletions src/layouts/basic-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { Layout } from 'antd';
import { connect } from 'dva';
import classNames from 'classnames';
import Policy from '@jiumao/policy';
import useMedia from 'react-media-hook2';
import { ContainerQuery } from 'react-container-query';
import DocumentTitle from 'react-document-title';
Expand All @@ -16,6 +17,7 @@ import './basic-layout.less';
interface IProps
extends Required<ConnectProps>, ISidebarMenuProps {
prefixCls?: string;
policy: Policy;
tabActiveKey?: string;
breadcrumbNameMap?: { [path: string]: IMenu };
setting?: ISettingModelState;
Expand Down Expand Up @@ -52,27 +54,24 @@ const BasicLayout: React.FC<IProps> = (props) => {
dispatch,
location,
route,
policy,
menuData,
breadcrumbNameMap,
setting,
children
} = props;
const { fixedHeader, theme } = setting;
const { prefixCls, ...restProps } = props;
const { routes, authority } = route!;
const { routes } = route!;

// constructor
useState(() => {
// 获取当前登录用户信息
// dispatch!({
// type: 'user/fetchCurrent'
// });
// 获取菜单数据
dispatch!({
type: 'menu/getMenuData',
payload: {
routes,
authority
policy
},
});
});
Expand Down Expand Up @@ -127,7 +126,8 @@ BasicLayout.defaultProps = {
prefixCls: 'lotus-basic-layout'
};

export default connect(({ menu, setting }: ConnectState) => ({
export default connect(({ menu, setting, user }: ConnectState) => ({
policy: user.policy,
menuData: menu.menuData,
breadcrumbNameMap: menu.breadcrumbNameMap,
setting
Expand Down
6 changes: 3 additions & 3 deletions src/layouts/copyright.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import { Icon } from 'antd';
import { APP_DEFAULT_CONFIG } from '@/config';
import defaultSettings from '@/config/default-settings';

const { companyName } = APP_DEFAULT_CONFIG;
const { company } = defaultSettings;

const Copyright = () => {
return (
<div>
Copyright <Icon type="copyright" /> 2019{companyName}技术部出品
Copyright <Icon type="copyright" /> 2019{company}技术部出品
</div>
)
};
Expand Down
71 changes: 44 additions & 27 deletions src/models/menu.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,57 @@
import { Reducer } from 'redux';
import memoizeOne from 'memoize-one';
import isEqual from 'lodash/isEqual';
import Policy from '@jiumao/policy';
import { formatMessage } from 'umi-plugin-react/locale';
import { Effect } from '@/models/connect';
import checkAuthority from '@/components/authorized/check-authority';
import { IMenu } from '@/components/sidebar-menu';
import defaultSettings from '@/config/default-settings';

const { menu } = defaultSettings;
let policy: Policy = null;

// 将路由数据转换为菜单数据
function formatter(
function formatterMenu(
data: IRoute[],
parentAuthority?: string[] | string,
parentName?: string,
): IMenu[] {
return data
.filter(item => item.name && item.path)
.map(item => {
const locale = `${parentName || 'menu'}.${item.name!}`;
// if enableMenuLocale use item.name,
// close menu international
const name = menu.disableLocal
? item.name!
: formatMessage({ id: locale, defaultMessage: item.name! });
const result: IMenu = {
...item,
name,
locale,
routes: void 0,
authority: item.authority || parentAuthority,
};
if (item.routes) {
// Reduce memory usage
result.children = formatter(item.routes, item.authority, locale);
let newMenus: IMenu[] = [];

const menus = data.filter(item => item.name && item.path);

menus.forEach(item => {
const locale = `${parentName || 'menu'}.${item.name!}`;

const name = menu.disableLocal
? item.name!
: formatMessage({ id: locale, defaultMessage: item.name! });

const result: IMenu = {
...item,
name,
locale,
routes: void 0,
authority: item.authority || undefined,
};

if (item.routes) {
// Reduce memory usage
result.children = formatterMenu(item.routes, locale);

if (!result.children.length) {
return;
}
return result;
});
}

// 检查权限
let authResult = checkAuthority(policy, result.authority);

if (authResult) {
newMenus.push(result);
}
});

return newMenus;
}

// 获取面包屑映射
Expand All @@ -54,7 +70,7 @@ const getBreadcrumbNameMap = (menuData: IMenu[]) => {
return routerMap;
};

const memoizeOneFormatter = memoizeOne(formatter, isEqual);
const memoizeOneFormatter = memoizeOne(formatterMenu, isEqual);
const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual);

// 过滤菜单数据
Expand Down Expand Up @@ -97,8 +113,9 @@ const MenuModel: IMenuModel = {
},
effects: {
*getMenuData({ payload, callback }, { put }) {
const { routes, authority } = payload;
const originalMenuData = memoizeOneFormatter(routes, authority);
const { routes } = payload;
policy = payload.policy;
const originalMenuData = memoizeOneFormatter(routes);
const menuData = filterMenuData(originalMenuData);
const breadcrumbNameMap = memoizeOneGetBreadcrumbNameMap(originalMenuData);

Expand Down
2 changes: 0 additions & 2 deletions src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ const UserModel: IUserModel = {
policy.addPolicy(item);
});

console.log(policy);

yield put({
type: 'saveCurrentUser',
payload: {
Expand Down
6 changes: 4 additions & 2 deletions src/pages/authorized.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ interface IProps extends ConnectProps {

const AuthComponent: React.FC<IProps> = (props) => {
const {
policy,
loading,
location,
children,
routerData,
dispatch
} = props;
let policy = props.policy;

React.useState(() => {
// 类似 Promise.all 实现比较合理,待优化
Expand Down Expand Up @@ -71,7 +71,9 @@ const AuthComponent: React.FC<IProps> = (props) => {
)
};

AuthComponent.defaultProps = {};
AuthComponent.defaultProps = {
policy: null
};

export default connect(({ menu, user, loading }: ConnectState) => ({
policy: user.policy,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/document.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="A admin dashboard application demo built upon Ant Design and Dva.js">
<link rel="icon" type="image/png" href="./favicon.png">
<link rel="icon" type="image/png" href="/react-admin-template/favicon.png">
<title>React Admin Template</title>
</head>
<body>
Expand Down
4 changes: 1 addition & 3 deletions src/utils/path-tools.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { parse, stringify } from 'qs';
import { parse } from 'qs';

export function parseQuery(data?: string) {
const url = data || window.location.href.split('?')[1];
return parse(url);
}

export function stringifyQuery() {}
12 changes: 0 additions & 12 deletions src/utils/regexp.ts

This file was deleted.

8 changes: 4 additions & 4 deletions src/utils/request.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import Axios, { AxiosRequestConfig } from 'axios';
import router from 'umi/router';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import { AXIOS_DEFAULT_CONFIG } from '@/config';
import { AJAX_DEFAULT_CONFIG } from '@/config';
import { getCookie } from '@/utils/cookie';

Axios.defaults.timeout = AXIOS_DEFAULT_CONFIG.timeout;
Axios.defaults.baseURL = AXIOS_DEFAULT_CONFIG.baseURL;
Axios.defaults.withCredentials = AXIOS_DEFAULT_CONFIG.withCredentials;
Axios.defaults.timeout = AJAX_DEFAULT_CONFIG.timeout;
Axios.defaults.baseURL = AJAX_DEFAULT_CONFIG.baseURL;
Axios.defaults.withCredentials = AJAX_DEFAULT_CONFIG.withCredentials;

function requestSuccess(config) {
// 请求开始,开启进度条
Expand Down

0 comments on commit 0d76dfd

Please sign in to comment.