Commit 028b6cc7 authored by 陈帅's avatar 陈帅

auto insert pro code

parent 41ad482a
...@@ -5,6 +5,7 @@ const exec = require('child_process').exec; ...@@ -5,6 +5,7 @@ const exec = require('child_process').exec;
const getNewRouteCode = require('./repalceRouter'); const getNewRouteCode = require('./repalceRouter');
const router = require('./router.config'); const router = require('./router.config');
const chalk = require('chalk'); const chalk = require('chalk');
const insertCode = require('./insertCode');
const fetchGithubFiles = async () => { const fetchGithubFiles = async () => {
const ignoreFile = ['_scripts']; const ignoreFile = ['_scripts'];
...@@ -123,3 +124,6 @@ const installBlock = async () => { ...@@ -123,3 +124,6 @@ const installBlock = async () => {
installGitFile(0); installGitFile(0);
}; };
installBlock(); installBlock();
// 插入 pro 需要的演示代码
insertCode();
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
const generate = require('@babel/generator');
const t = require('@babel/types');
const fs = require('fs');
const path = require('path');
const prettier = require('prettier');
const chalk = require('chalk');
const parseCode = code => {
return parser.parse(code, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
}).program.body[0];
};
/**
* 生成代码
* @param {*} ast
*/
function generateCode(ast) {
const newCode = generate.default(ast, {}).code;
return prettier.format(newCode, {
// format same as ant-design-pro
singleQuote: true,
trailingComma: 'es5',
printWidth: 100,
parser: 'typescript',
});
}
const SettingCodeString = `
<SettingDrawer
settings={settings}
onSettingChange={config =>
dispatch!({
type: 'settings/changeSetting',
payload: config,
})
}
/>
`;
const mapAst = (configPath, callBack) => {
const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
// 查询当前配置文件是否导出 routes 属性
traverse.default(ast, {
Program({ node }) {
const { body } = node;
callBack(body);
},
});
return generateCode(ast);
};
const insertBasicLayout = configPath => {
return mapAst(configPath, body => {
const index = body.findIndex(item => {
return item.type !== 'ImportDeclaration';
});
// 从组件中导入 CopyBlock
body.splice(
index,
0,
parseCode(`import CopyBlock from '@/components/CopyBlock';
`),
);
body.forEach(item => {
// 从包中导出 SettingDrawer
if (item.type === 'ImportDeclaration') {
if (item.source.value === '@ant-design/pro-layout') {
item.specifiers.push(parseCode(`SettingDrawer`).expression);
}
}
if (item.type === 'VariableDeclaration') {
const {
id,
init: { body },
} = item.declarations[0];
// 给 BasicLayout 中插入 button 和 设置抽屉
if (id.name === `BasicLayout`) {
body.body.forEach(node => {
if (node.type === 'ReturnStatement') {
const JSXFragment = parseCode(`<></>`).expression;
JSXFragment.children.push({ ...node.argument });
JSXFragment.children.push(parseCode(SettingCodeString).expression);
JSXFragment.children.push(parseCode(` <CopyBlock />`).expression);
node.argument = JSXFragment;
}
});
}
}
});
});
};
const insertRightContent = configPath => {
return mapAst(configPath, body => {
const index = body.findIndex(item => {
return item.type !== 'ImportDeclaration';
});
// 从组件中导入 CopyBlock
body.splice(index, 0, parseCode(`import NoticeIconView from './NoticeIconView';`));
body.forEach(item => {
if (item.type === 'ClassDeclaration') {
const classBody = item.body.body[0].body;
classBody.body.forEach(node => {
if (node.type === 'ReturnStatement') {
const index = node.argument.children.findIndex(item => {
if (item.type === 'JSXElement') {
if (item.openingElement.name.name === 'Avatar') {
return true;
}
}
});
node.argument.children.splice(index, 1, parseCode(`<Avatar menu />`).expression);
node.argument.children.splice(index, 0, parseCode(`<NoticeIconView />`).expression);
}
});
}
});
});
};
module.exports = () => {
const basicLayoutPath = path.join(__dirname, '../src/layouts/BasicLayout.tsx');
fs.writeFileSync(basicLayoutPath, insertBasicLayout(basicLayoutPath));
console.log(`insert ${chalk.hex('#1890ff')('BasicLayout')} success`);
const rightContentPath = path.join(__dirname, '../src/components/GlobalHeader/RightContent.tsx');
fs.writeFileSync(rightContentPath, insertRightContent(rightContentPath));
console.log(`insert ${chalk.hex('#1890ff')('RightContent')} success`);
};
...@@ -5,7 +5,7 @@ const t = require('@babel/types'); ...@@ -5,7 +5,7 @@ const t = require('@babel/types');
const fs = require('fs'); const fs = require('fs');
const prettier = require('prettier'); const prettier = require('prettier');
const getNewRouteCode = (configPath, newRoute, absSrcPath) => { const getNewRouteCode = (configPath, newRoute) => {
const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), { const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), {
sourceType: 'module', sourceType: 'module',
plugins: ['typescript'], plugins: ['typescript'],
......
import React from 'react'; import React from 'react';
import { Icon, Typography, Popover } from 'antd'; import { Icon, Typography, Popover } from 'antd';
import styles from './index.less'; import styles from './index.less';
import { connect } from 'dva';
import * as H from 'history';
const firstUpperCase = (pathString: string) => { const firstUpperCase = (pathString: string) => {
return pathString return pathString
.replace('.', '') .replace('.', '')
...@@ -22,7 +24,12 @@ const BlockCodeView: React.SFC<{ ...@@ -22,7 +24,12 @@ const BlockCodeView: React.SFC<{
); );
}; };
export default ({ url }: { url: string }) => { type RoutingType = { location: H.Location };
export default connect(({ routing }: { routing: RoutingType }) => ({
location: routing.location,
}))(({ location }: RoutingType) => {
const url = location.pathname;
return ( return (
<Popover <Popover
title="下载此页面到本地项目" title="下载此页面到本地项目"
...@@ -35,4 +42,4 @@ export default ({ url }: { url: string }) => { ...@@ -35,4 +42,4 @@ export default ({ url }: { url: string }) => {
</div> </div>
</Popover> </Popover>
); );
}; });
import React from 'react';
import { Avatar, Menu, Spin, Icon } from 'antd';
import { FormattedMessage } from 'umi-plugin-react/locale';
import { ClickParam } from 'antd/lib/menu';
import { ConnectProps, ConnectState } from '@/models/connect';
import { CurrentUser } from '@/models/user';
import { connect } from 'dva';
import router from 'umi/router';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
export interface GlobalHeaderRightProps extends ConnectProps {
currentUser?: CurrentUser;
menu?: boolean;
}
class AvatarDropdown extends React.Component<GlobalHeaderRightProps> {
onMenuClick = (event: ClickParam) => {
const { key } = event;
if (key === 'logout') {
const { dispatch } = this.props;
dispatch!({
type: 'login/logout',
});
return;
}
router.push(`/account/${key}`);
};
render() {
const { currentUser = {}, menu } = this.props;
if (!menu) {
return (
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
<span className={styles.name}>{currentUser.name}</span>
</span>
);
}
const menuHeaderDropdown = (
<Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
<Menu.Item key="center">
<Icon type="user" />
<FormattedMessage id="menu.account.center" defaultMessage="account center" />
</Menu.Item>
<Menu.Item key="settings">
<Icon type="setting" />
<FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
</Menu.Item>
<Menu.Divider />
<Menu.Item key="logout">
<Icon type="logout" />
<FormattedMessage id="menu.account.logout" defaultMessage="logout" />
</Menu.Item>
</Menu>
);
return currentUser && currentUser.name ? (
<HeaderDropdown overlay={menuHeaderDropdown}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
<span className={styles.name}>{currentUser.name}</span>
</span>
</HeaderDropdown>
) : (
<Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
);
}
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.currentUser,
}))(AvatarDropdown);
import { ConnectProps, ConnectState } from '@/models/connect';
import { NoticeItem } from '@/models/global';
import { CurrentUser } from '@/models/user';
import React, { Component } from 'react';
import { Tag, message } from 'antd';
import { formatMessage } from 'umi-plugin-react/locale';
import moment from 'moment';
import groupBy from 'lodash/groupBy';
import NoticeIcon from '../NoticeIcon';
import styles from './index.less';
import { connect } from 'dva';
export interface GlobalHeaderRightProps extends ConnectProps {
notices?: NoticeItem[];
currentUser?: CurrentUser;
fetchingNotices?: boolean;
onNoticeVisibleChange?: (visible: boolean) => void;
onNoticeClear?: (tabName?: string) => void;
}
class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
getNoticeData = (): { [key: string]: NoticeItem[] } => {
const { notices = [] } = this.props;
if (notices.length === 0) {
return {};
}
const newNotices = notices.map(notice => {
const newNotice = { ...notice };
if (newNotice.datetime) {
newNotice.datetime = moment(notice.datetime as string).fromNow();
}
if (newNotice.id) {
newNotice.key = newNotice.id;
}
if (newNotice.extra && newNotice.status) {
const color = {
todo: '',
processing: 'blue',
urgent: 'red',
doing: 'gold',
}[newNotice.status];
newNotice.extra = (
<Tag color={color} style={{ marginRight: 0 }}>
{newNotice.extra}
</Tag>
);
}
return newNotice;
});
return groupBy(newNotices, 'type');
};
getUnreadData = (noticeData: { [key: string]: NoticeItem[] }) => {
const unreadMsg: { [key: string]: number } = {};
Object.entries(noticeData).forEach(([key, value]) => {
if (!unreadMsg[key]) {
unreadMsg[key] = 0;
}
if (Array.isArray(value)) {
unreadMsg[key] = value.filter(item => !item.read).length;
}
});
return unreadMsg;
};
changeReadState = (clickedItem: NoticeItem) => {
const { id } = clickedItem;
const { dispatch } = this.props;
dispatch!({
type: 'global/changeNoticeReadState',
payload: id,
});
};
componentDidMount() {
const { dispatch } = this.props;
dispatch!({
type: 'global/fetchNotices',
});
}
handleNoticeClear = (title: string, key: string) => {
const { dispatch } = this.props;
message.success(`${formatMessage({ id: 'component.noticeIcon.cleared' })} ${title}`);
if (dispatch) {
dispatch({
type: 'global/clearNotices',
payload: key,
});
}
};
render() {
const { currentUser, fetchingNotices, onNoticeVisibleChange } = this.props;
const noticeData = this.getNoticeData();
const unreadMsg = this.getUnreadData(noticeData);
return (
<NoticeIcon
className={styles.action}
count={currentUser && currentUser.unreadCount}
onItemClick={item => {
this.changeReadState(item as NoticeItem);
}}
loading={fetchingNotices}
clearText={formatMessage({ id: 'component.noticeIcon.clear' })}
viewMoreText={formatMessage({ id: 'component.noticeIcon.view-more' })}
onClear={this.handleNoticeClear}
onPopupVisibleChange={onNoticeVisibleChange}
onViewMore={() => message.info('Click on view more')}
clearClose
>
<NoticeIcon.Tab
tabKey="notification"
count={unreadMsg.notification}
list={noticeData.notification}
title={formatMessage({ id: 'component.globalHeader.notification' })}
emptyText={formatMessage({ id: 'component.globalHeader.notification.empty' })}
showViewMore
/>
<NoticeIcon.Tab
tabKey="message"
count={unreadMsg.message}
list={noticeData.message}
title={formatMessage({ id: 'component.globalHeader.message' })}
emptyText={formatMessage({ id: 'component.globalHeader.message.empty' })}
showViewMore
/>
<NoticeIcon.Tab
tabKey="event"
title={formatMessage({ id: 'component.globalHeader.event' })}
emptyText={formatMessage({ id: 'component.globalHeader.event.empty' })}
count={unreadMsg.event}
list={noticeData.event}
showViewMore
/>
</NoticeIcon>
);
}
}
export default connect(({ user, global, loading }: ConnectState) => ({
currentUser: user.currentUser,
collapsed: global.collapsed,
fetchingMoreNotices: loading.effects['global/fetchMoreNotices'],
fetchingNotices: loading.effects['global/fetchNotices'],
notices: global.notices,
}))(GlobalHeaderRight);
import { ConnectProps, ConnectState } from '@/models/connect'; import { ConnectProps, ConnectState } from '@/models/connect';
import { NoticeItem } from '@/models/global';
import { CurrentUser } from '@/models/user';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Spin, Tag, Menu, Icon, Avatar, Tooltip, message } from 'antd'; import { Icon, Tooltip } from 'antd';
import { ClickParam } from 'antd/lib/menu'; import { formatMessage } from 'umi-plugin-react/locale';
import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import moment from 'moment';
import groupBy from 'lodash/groupBy';
import NoticeIcon from '../NoticeIcon';
import HeaderSearch from '../HeaderSearch'; import HeaderSearch from '../HeaderSearch';
import HeaderDropdown from '../HeaderDropdown';
import SelectLang from '../SelectLang'; import SelectLang from '../SelectLang';
import styles from './index.less'; import styles from './index.less';
import Avatar from './AvatarDropdown';
import { connect } from 'dva'; import { connect } from 'dva';
import router from 'umi/router';
export type SiderTheme = 'light' | 'dark'; export type SiderTheme = 'light' | 'dark';
export interface GlobalHeaderRightProps extends ConnectProps { export interface GlobalHeaderRightProps extends ConnectProps {
notices?: NoticeItem[];
currentUser?: CurrentUser;
fetchingNotices?: boolean;
onNoticeVisibleChange?: (visible: boolean) => void;
onMenuClick?: (param: ClickParam) => void;
onNoticeClear?: (tabName?: string) => void;
theme?: SiderTheme; theme?: SiderTheme;
layout: 'sidemenu' | 'topmenu';
} }
class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
getNoticeData = (): { [key: string]: NoticeItem[] } => {
const { notices = [] } = this.props;
if (notices.length === 0) {
return {};
}
const newNotices = notices.map(notice => {
const newNotice = { ...notice };
if (newNotice.datetime) {
newNotice.datetime = moment(notice.datetime as string).fromNow();
}
if (newNotice.id) {
newNotice.key = newNotice.id;
}
if (newNotice.extra && newNotice.status) {
const color = {
todo: '',
processing: 'blue',
urgent: 'red',
doing: 'gold',
}[newNotice.status];
newNotice.extra = (
<Tag color={color} style={{ marginRight: 0 }}>
{newNotice.extra}
</Tag>
);
}
return newNotice;
});
return groupBy(newNotices, 'type');
};
getUnreadData = (noticeData: { [key: string]: NoticeItem[] }) => {
const unreadMsg: { [key: string]: number } = {};
Object.entries(noticeData).forEach(([key, value]) => {
if (!unreadMsg[key]) {
unreadMsg[key] = 0;
}
if (Array.isArray(value)) {
unreadMsg[key] = value.filter(item => !item.read).length;
}
});
return unreadMsg;
};
changeReadState = (clickedItem: NoticeItem) => {
const { id } = clickedItem;
const { dispatch } = this.props;
dispatch!({
type: 'global/changeNoticeReadState',
payload: id,
});
};
componentDidMount() {
const { dispatch } = this.props;
dispatch!({
type: 'global/fetchNotices',
});
}
handleNoticeClear = (title: string, key: string) => {
const { dispatch } = this.props;
message.success(`${formatMessage({ id: 'component.noticeIcon.cleared' })} ${title}`);
if (dispatch) {
dispatch({
type: 'global/clearNotices',
payload: key,
});
}
};
onMenuClick = (event: ClickParam) => {
const { onMenuClick } = this.props;
if (onMenuClick) {
onMenuClick(event);
return;
}
const { key } = event;
if (key === 'logout') {
const { dispatch } = this.props;
dispatch!({
type: 'login/logout',
});
return;
}
router.push(`/account/${key}`);
};
render() { render() {
const { currentUser, fetchingNotices, onNoticeVisibleChange, theme } = this.props; const { theme, layout } = this.props;
const menu = (
<Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
<Menu.Item key="center">
<Icon type="user" />
<FormattedMessage id="menu.account.center" defaultMessage="account center" />
</Menu.Item>
<Menu.Item key="settings">
<Icon type="setting" />
<FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
</Menu.Item>
<Menu.Divider />
<Menu.Item key="logout">
<Icon type="logout" />
<FormattedMessage id="menu.account.logout" defaultMessage="logout" />
</Menu.Item>
</Menu>
);
const noticeData = this.getNoticeData();
const unreadMsg = this.getUnreadData(noticeData);
let className = styles.right; let className = styles.right;
if (theme === 'dark') {
if (theme === 'dark' && layout === 'topmenu') {
className = `${styles.right} ${styles.dark}`; className = `${styles.right} ${styles.dark}`;
} }
return ( return (
<div className={className}> <div className={className}>
<HeaderSearch <HeaderSearch
className={`${styles.action} ${styles.search}`} className={`${styles.action} ${styles.search}`}
placeholder={formatMessage({ id: 'component.globalHeader.search' })} placeholder={formatMessage({
id: 'component.globalHeader.search',
})}
dataSource={[ dataSource={[
formatMessage({ id: 'component.globalHeader.search.example1' }), formatMessage({
formatMessage({ id: 'component.globalHeader.search.example2' }), id: 'component.globalHeader.search.example1',
formatMessage({ id: 'component.globalHeader.search.example3' }), }),
formatMessage({
id: 'component.globalHeader.search.example2',
}),
formatMessage({
id: 'component.globalHeader.search.example3',
}),
]} ]}
onSearch={value => { onSearch={value => {
console.log('input', value); // tslint:disable-line no-console console.log('input', value); // tslint:disable-line no-console
...@@ -155,7 +47,11 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { ...@@ -155,7 +47,11 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
console.log('enter', value); // tslint:disable-line no-console console.log('enter', value); // tslint:disable-line no-console
}} }}
/> />
<Tooltip title={formatMessage({ id: 'component.globalHeader.help' })}> <Tooltip
title={formatMessage({
id: 'component.globalHeader.help',
})}
>
<a <a
target="_blank" target="_blank"
href="https://pro.ant.design/docs/getting-started" href="https://pro.ant.design/docs/getting-started"
...@@ -165,71 +61,14 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { ...@@ -165,71 +61,14 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
<Icon type="question-circle-o" /> <Icon type="question-circle-o" />
</a> </a>
</Tooltip> </Tooltip>
<Avatar />
<NoticeIcon
className={styles.action}
count={currentUser && currentUser.unreadCount}
onItemClick={item => {
this.changeReadState(item as NoticeItem);
}}
loading={fetchingNotices}
clearText={formatMessage({ id: 'component.noticeIcon.clear' })}
viewMoreText={formatMessage({ id: 'component.noticeIcon.view-more' })}
onClear={this.handleNoticeClear}
onPopupVisibleChange={onNoticeVisibleChange}
onViewMore={() => message.info('Click on view more')}
clearClose
>
<NoticeIcon.Tab
tabKey="notification"
count={unreadMsg.notification}
list={noticeData.notification}
title={formatMessage({ id: 'component.globalHeader.notification' })}
emptyText={formatMessage({ id: 'component.globalHeader.notification.empty' })}
showViewMore
/>
<NoticeIcon.Tab
tabKey="message"
count={unreadMsg.message}
list={noticeData.message}
title={formatMessage({ id: 'component.globalHeader.message' })}
emptyText={formatMessage({ id: 'component.globalHeader.message.empty' })}
showViewMore
/>
<NoticeIcon.Tab
tabKey="event"
title={formatMessage({ id: 'component.globalHeader.event' })}
emptyText={formatMessage({ id: 'component.globalHeader.event.empty' })}
count={unreadMsg.event}
list={noticeData.event}
showViewMore
/>
</NoticeIcon>
{currentUser && currentUser.name ? (
<HeaderDropdown overlay={menu}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar
size="small"
className={styles.avatar}
src={currentUser.avatar}
alt="avatar"
/>
<span className={styles.name}>{currentUser.name}</span>
</span>
</HeaderDropdown>
) : (
<Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
)}
<SelectLang className={styles.action} /> <SelectLang className={styles.action} />
</div> </div>
); );
} }
} }
export default connect(({ user, global, loading }: ConnectState) => ({ export default connect(({ settings }: ConnectState) => ({
currentUser: user.currentUser, theme: settings.navTheme,
collapsed: global.collapsed, layout: settings.layout,
fetchingMoreNotices: loading.effects['global/fetchMoreNotices'],
fetchingNotices: loading.effects['global/fetchNotices'],
notices: global.notices,
}))(GlobalHeaderRight); }))(GlobalHeaderRight);
import { ConnectState, ConnectProps } from '@/models/connect'; import { ConnectState, ConnectProps } from '@/models/connect';
import RightContent from '@/components/GlobalHeader/RightContent'; import RightContent from '@/components/GlobalHeader/RightContent';
import CopyBlock from '@/components/CopyBlock';
import { connect } from 'dva'; import { connect } from 'dva';
import React, { useState } from 'react'; import React, { useState } from 'react';
import logo from '../assets/logo.svg'; import logo from '../assets/logo.svg';
...@@ -11,30 +10,26 @@ import { ...@@ -11,30 +10,26 @@ import {
BasicLayoutProps as BasicLayoutComponentsProps, BasicLayoutProps as BasicLayoutComponentsProps,
MenuDataItem, MenuDataItem,
Settings, Settings,
SettingDrawer,
} from '@ant-design/pro-layout'; } from '@ant-design/pro-layout';
import Link from 'umi/link'; import Link from 'umi/link';
import { isAntDesignProOrDev } from '@/utils/utils';
export interface BasicLayoutProps extends BasicLayoutComponentsProps, ConnectProps { export interface BasicLayoutProps extends BasicLayoutComponentsProps, ConnectProps {
breadcrumbNameMap: { [path: string]: MenuDataItem }; breadcrumbNameMap: {
[path: string]: MenuDataItem;
};
settings: Settings; settings: Settings;
} }
export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & { export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
breadcrumbNameMap: { [path: string]: MenuDataItem }; breadcrumbNameMap: {
[path: string]: MenuDataItem;
};
}; };
/** /**
* use Authorized check all menu item * use Authorized check all menu item
*/ */
const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] => { const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] => {
return menuList.map(item => { return menuList.map(item => {
const localItem = { const localItem = { ...item, children: item.children ? menuDataRender(item.children) : [] };
...item,
children: item.children ? menuDataRender(item.children) : [],
};
return Authorized.check(item.authority, localItem, null) as MenuDataItem; return Authorized.check(item.authority, localItem, null) as MenuDataItem;
}); });
}; };
...@@ -44,57 +39,52 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => { ...@@ -44,57 +39,52 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
/** /**
* constructor * constructor
*/ */
useState(() => { useState(() => {
dispatch!({ type: 'user/fetchCurrent' }); dispatch!({
dispatch!({ type: 'settings/getSetting' }); type: 'user/fetchCurrent',
});
dispatch!({
type: 'settings/getSetting',
});
}); });
/** /**
* init variables * init variables
*/ */
const handleMenuCollapse = (payload: boolean) => const handleMenuCollapse = (payload: boolean) =>
dispatch!({ type: 'global/changeLayoutCollapsed', payload }); dispatch!({
type: 'global/changeLayoutCollapsed',
payload,
});
return ( return (
<> <BasicLayoutComponents
<BasicLayoutComponents logo={logo}
logo={logo} onCollapse={handleMenuCollapse}
onCollapse={handleMenuCollapse} menuItemRender={(menuItemProps, defaultDom) => {
menuItemRender={(menuItemProps, defaultDom) => { return <Link to={menuItemProps.path}>{defaultDom}</Link>;
return <Link to={menuItemProps.path}>{defaultDom}</Link>; }}
}} breadcrumbRender={(routers = []) => {
breadcrumbRender={(routers = []) => { return [
return [ {
{ path: '/',
path: '/', breadcrumbName: formatMessage({
breadcrumbName: formatMessage({ id: 'menu.home',
id: 'menu.home', defaultMessage: 'Home',
defaultMessage: 'Home', }),
}), },
}, ...routers,
...routers, ];
]; }}
}} menuDataRender={menuDataRender}
menuDataRender={menuDataRender} formatMessage={formatMessage}
formatMessage={formatMessage} rightContentRender={rightProps => <RightContent {...rightProps} />}
rightContentRender={rightProps => <RightContent {...rightProps} />} {...props}
{...props} {...settings}
{...settings} >
> {children}
{children} </BasicLayoutComponents>
</BasicLayoutComponents>
{isAntDesignProOrDev() && (
<SettingDrawer
settings={settings}
onSettingChange={config =>
dispatch!({
type: 'settings/changeSetting',
payload: config,
})
}
/>
)}
{isAntDesignProOrDev() && <CopyBlock url={location!.pathname} />}
</>
); );
}; };
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment