Commit 6c519bb2 authored by 陈帅's avatar 陈帅

commit

parent 0d5b157e
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');
const generate = require('@babel/generator');
const t = require('@babel/types');
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const fetch = require('node-fetch');
const exec = require('child_process').exec; const exec = require('child_process').exec;
const getNewRouteCode = require('./repalceRouter');
const prettier = require('prettier');
const router = require('./router.config'); const router = require('./router.config');
const getNewRouteCode = (configPath, newRoute, absSrcPath) => {
const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), {
sourceType: 'module',
plugins: ['typescript'],
});
let routesNode = null;
const importModules = [];
// 查询当前配置文件是否导出 routes 属性
traverse.default(ast, {
Program({ node }) {
// find import
const { body } = node;
body.forEach(item => {
if (t.isImportDeclaration(item)) {
const { specifiers } = item;
const defaultEpecifier = specifiers.find(s => {
return t.isImportDefaultSpecifier(s) && t.isIdentifier(s.local);
});
if (defaultEpecifier && t.isStringLiteral(item.source)) {
importModules.push({
identifierName: defaultEpecifier.local.name,
modulePath: item.source.value,
});
}
}
});
},
ObjectExpression({ node, parent }) {
// find routes on object, like { routes: [] }
if (t.isArrayExpression(parent)) {
// children routes
return;
}
const { properties } = node;
properties.forEach(p => {
const { key, value } = p;
if (t.isObjectProperty(p) && t.isIdentifier(key) && key.name === 'routes') {
if (value) {
// find json file program expression
(p.value = parser.parse(JSON.stringify(newRoute)).program.body[0].expression),
(routesNode = value);
}
}
});
},
});
if (routesNode) {
const code = generateCode(ast);
return { code, routesPath: configPath };
} else {
throw new Error('route array config not found.');
}
};
/**
* 生成代码
* @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 relativePath = path.join(__dirname, '../config/config.ts'); const relativePath = path.join(__dirname, '../config/config.ts');
const filterParentRouter = router => {
return [...router]
.map(item => {
if (item.routes) {
return { ...item, routes: filterParentRouter(item.routes) };
}
return null;
})
.filter(item => item);
};
const parentRouter = filterParentRouter(router);
const { routesPath, code } = getNewRouteCode(relativePath, parentRouter);
// write ParentRouter
fs.writeFileSync(routesPath, code);
const findAllInstallRouter = router => { const findAllInstallRouter = router => {
let routers = []; let routers = [];
router.forEach(item => { router.forEach(item => {
...@@ -116,8 +27,16 @@ const findAllInstallRouter = router => { ...@@ -116,8 +27,16 @@ const findAllInstallRouter = router => {
return routers; return routers;
}; };
const installRouters = findAllInstallRouter(router); const filterParentRouter = router => {
let i = 0; return [...router]
.map(item => {
if (item.routes) {
return { ...item, routes: filterParentRouter(item.routes) };
}
return null;
})
.filter(item => item);
};
const firstUpperCase = pathString => { const firstUpperCase = pathString => {
return pathString return pathString
.replace('.', '') .replace('.', '')
...@@ -126,7 +45,29 @@ const firstUpperCase = pathString => { ...@@ -126,7 +45,29 @@ const firstUpperCase = pathString => {
.filter(s => s) .filter(s => s)
.join(''); .join('');
}; };
const execCmd = shell => {
return new Promise((resolve, reject) => {
exec(shell, { encoding: 'utf8' }, (error, statusbar) => {
if (error) {
console.log(error);
return reject(error);
}
console.log(statusbar);
resolve();
});
});
};
// replace router config
const parentRouter = filterParentRouter(router);
const { routesPath, code } = getNewRouteCode(relativePath, parentRouter);
// write ParentRouter
fs.writeFileSync(routesPath, code);
const installBlock = () => { const installBlock = () => {
const installRouters = findAllInstallRouter(router);
const installBlockIteration = async i => {
const item = installRouters[i]; const item = installRouters[i];
if (!item || !item.path) { if (!item || !item.path) {
...@@ -136,12 +77,12 @@ const installBlock = () => { ...@@ -136,12 +77,12 @@ const installBlock = () => {
const cmd = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${firstUpperCase( const cmd = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${firstUpperCase(
item.path, item.path,
)} --npm-client=cnpm --path=${item.path}`; )} --npm-client=cnpm --path=${item.path}`;
console.log(cmd); const data = await fetch(
exec(cmd, { encoding: 'utf8' }, (error, statusbar) => { ` https://github.com/ant-design/pro-blocks/tree/master/${firstUpperCase(item.path)}`,
if (error) console.log(error); );
console.log(statusbar); await execCmd(cmd);
i += 1; installBlockIteration(i + 1);
installBlock(); };
}); installBlockIteration(0);
}; };
installBlock(); installBlock();
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 prettier = require('prettier');
const getNewRouteCode = (configPath, newRoute, absSrcPath) => {
const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), {
sourceType: 'module',
plugins: ['typescript'],
});
let routesNode = null;
const importModules = [];
// 查询当前配置文件是否导出 routes 属性
traverse.default(ast, {
Program({ node }) {
// find import
const { body } = node;
body.forEach(item => {
if (t.isImportDeclaration(item)) {
const { specifiers } = item;
const defaultEpecifier = specifiers.find(s => {
return t.isImportDefaultSpecifier(s) && t.isIdentifier(s.local);
});
if (defaultEpecifier && t.isStringLiteral(item.source)) {
importModules.push({
identifierName: defaultEpecifier.local.name,
modulePath: item.source.value,
});
}
}
});
},
ObjectExpression({ node, parent }) {
// find routes on object, like { routes: [] }
if (t.isArrayExpression(parent)) {
// children routes
return;
}
const { properties } = node;
properties.forEach(p => {
const { key, value } = p;
if (t.isObjectProperty(p) && t.isIdentifier(key) && key.name === 'routes') {
if (value) {
// find json file program expression
(p.value = parser.parse(JSON.stringify(newRoute)).program.body[0].expression),
(routesNode = value);
}
}
});
},
});
if (routesNode) {
const code = generateCode(ast);
return { code, routesPath: configPath };
} else {
throw new Error('route array config not found.');
}
};
/**
* 生成代码
* @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',
});
}
module.exports = getNewRouteCode;
...@@ -57,12 +57,12 @@ module.exports = [ ...@@ -57,12 +57,12 @@ module.exports = [
{ {
path: '/form/basic-form', path: '/form/basic-form',
name: 'basicform', name: 'basicform',
component: './Forms/BasicForm', component: './Form/BasicForm',
}, },
{ {
path: '/form/step-form', path: '/form/step-form',
name: 'stepform', name: 'stepform',
component: './Forms/StepForm', component: './Form/StepForm',
hideChildrenInMenu: true, hideChildrenInMenu: true,
// routes: [ // routes: [
// { // {
...@@ -72,17 +72,17 @@ module.exports = [ ...@@ -72,17 +72,17 @@ module.exports = [
// { // {
// path: '/form/step-form/info', // path: '/form/step-form/info',
// name: 'info', // name: 'info',
// component: './Forms/StepForm/Step1', // component: './Form/StepForm/Step1',
// }, // },
// { // {
// path: '/form/step-form/confirm', // path: '/form/step-form/confirm',
// name: 'confirm', // name: 'confirm',
// component: './Forms/StepForm/Step2', // component: './Form/StepForm/Step2',
// }, // },
// { // {
// path: '/form/step-form/result', // path: '/form/step-form/result',
// name: 'result', // name: 'result',
// component: './Forms/StepForm/Step3', // component: './Form/StepForm/Step3',
// }, // },
// ], // ],
}, },
...@@ -90,7 +90,7 @@ module.exports = [ ...@@ -90,7 +90,7 @@ module.exports = [
path: '/form/advanced-form', path: '/form/advanced-form',
name: 'advancedform', name: 'advancedform',
authority: ['admin'], authority: ['admin'],
component: './Forms/AdvancedForm', component: './Form/AdvancedForm',
}, },
], ],
}, },
...@@ -103,22 +103,22 @@ module.exports = [ ...@@ -103,22 +103,22 @@ module.exports = [
{ {
path: '/list/table-list', path: '/list/table-list',
name: 'searchtable', name: 'searchtable',
component: './List/TableList', component: './list/Tablelist',
}, },
{ {
path: '/list/basic-list', path: '/list/basic-list',
name: 'basiclist', name: 'basiclist',
component: './List/BasicList', component: './list/Basiclist',
}, },
{ {
path: '/list/card-list', path: '/list/card-list',
name: 'cardlist', name: 'cardlist',
component: './List/CardList', component: './list/Cardlist',
}, },
{ {
path: '/list/search', path: '/list/search',
name: 'search-list', name: 'search-list',
component: './List/List', component: './list/search',
routes: [ routes: [
{ {
path: '/list/search', path: '/list/search',
...@@ -127,17 +127,17 @@ module.exports = [ ...@@ -127,17 +127,17 @@ module.exports = [
{ {
path: '/list/search/articles', path: '/list/search/articles',
name: 'articles', name: 'articles',
component: './List/Articles', component: './list/Articles',
}, },
{ {
path: '/list/search/projects', path: '/list/search/projects',
name: 'projects', name: 'projects',
component: './List/Projects', component: './list/Projects',
}, },
{ {
path: '/list/search/applications', path: '/list/search/applications',
name: 'applications', name: 'applications',
component: './List/Applications', component: './list/Applications',
}, },
], ],
}, },
...@@ -202,12 +202,6 @@ module.exports = [ ...@@ -202,12 +202,6 @@ module.exports = [
name: 'server-error', name: 'server-error',
component: './Exception/500', component: './Exception/500',
}, },
{
path: '/exception/trigger',
name: 'trigger',
hideInMenu: true,
component: './Exception/TriggerException',
},
], ],
}, },
{ {
......
.copy-block {
position: absolute;
right: 80px;
bottom: 40px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 80px;
height: 80px;
font-size: 20px;
background: #fff;
border-radius: 40px;
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14),
0 1px 10px 0 rgba(0, 0, 0, 0.12);
cursor: pointer;
.copy-block-text {
font-size: 12px;
}
}
.copy-block-code {
color: #fff;
background: #000;
}
import React from 'react';
import { Icon, Typography, Tooltip } from 'antd';
import styles from './index.less';
const firstUpperCase = (pathString: string) => {
return pathString
.replace('.', '')
.split(/\/|\-/)
.map(s => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase()))
.filter(s => s)
.join('');
};
const BlockCodeView: React.SFC<{
url: string;
}> = ({ url }) => {
console.log(url);
const blockUrl = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${firstUpperCase(
url,
)} --npm-client=cnpm --path=${url}`;
return (
<div>
<Typography.Paragraph copyable>
<code className={styles['copy-block-code']}>{blockUrl}</code>
</Typography.Paragraph>
</div>
);
};
export default ({ url }: { url: string }) => {
return (
<Tooltip placement="topLeft" title={<BlockCodeView url={url} />} trigger="click">
<div className={styles['copy-block']}>
<Icon type="code" />
<div className={styles['copy-block-text']}>
下载到
<br />
项目中
</div>
</div>
</Tooltip>
);
};
...@@ -3,7 +3,7 @@ import { NoticeItem } from '@/models/global'; ...@@ -3,7 +3,7 @@ import { NoticeItem } from '@/models/global';
import { CurrentUser } from '@/models/user'; 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 { Spin, Tag, Menu, Icon, Avatar, Tooltip, message } from 'antd';
import { ClickParam } from 'antd/es/menu'; import { ClickParam } from 'antd/lib/menu';
import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale'; import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale';
import moment from 'moment'; import moment from 'moment';
import groupBy from 'lodash/groupBy'; import groupBy from 'lodash/groupBy';
...@@ -13,6 +13,7 @@ import HeaderDropdown from '../HeaderDropdown'; ...@@ -13,6 +13,7 @@ import HeaderDropdown from '../HeaderDropdown';
import SelectLang from '../SelectLang'; import SelectLang from '../SelectLang';
import styles from './index.less'; import styles from './index.less';
import { connect } from 'dva'; import { connect } from 'dva';
import router from 'umi/router';
export type SiderTheme = 'light' | 'dark'; export type SiderTheme = 'light' | 'dark';
...@@ -95,27 +96,32 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { ...@@ -95,27 +96,32 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
}); });
} }
}; };
onMenuClick = (event: ClickParam) => {
const { onMenuClick } = this.props;
if (onMenuClick) {
onMenuClick(event);
return;
}
const { key } = event;
router.push(`/account/${key}`);
};
render() { render() {
const { currentUser, fetchingNotices, onNoticeVisibleChange, onMenuClick, theme } = this.props; const { currentUser, fetchingNotices, onNoticeVisibleChange, theme } = this.props;
const menu = ( const menu = (
<Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}> <Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
<Menu.Item key="userCenter"> <Menu.Item key="center">
<Icon type="user" /> <Icon type="user" />
<FormattedMessage id="menu.account.center" defaultMessage="account center" /> <FormattedMessage id="menu.account.center" defaultMessage="account center" />
</Menu.Item> </Menu.Item>
<Menu.Item key="userinfo"> <Menu.Item key="settings">
<Icon type="setting" /> <Icon type="setting" />
<FormattedMessage id="menu.account.settings" defaultMessage="account settings" /> <FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
</Menu.Item> </Menu.Item>
<Menu.Item key="triggerError"> {/* <Menu.Divider /> */}
<Icon type="close-circle" /> {/* <Menu.Item key="logout">
<FormattedMessage id="menu.account.trigger" defaultMessage="Trigger Error" />
</Menu.Item>
<Menu.Divider />
<Menu.Item key="logout">
<Icon type="logout" /> <Icon type="logout" />
<FormattedMessage id="menu.account.logout" defaultMessage="logout" /> <FormattedMessage id="menu.account.logout" defaultMessage="logout" />
</Menu.Item> </Menu.Item> */}
</Menu> </Menu>
); );
const noticeData = this.getNoticeData(); const noticeData = this.getNoticeData();
......
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';
...@@ -42,7 +43,7 @@ const filterMenuData = (menuList: MenuDataItem[], locale: boolean): MenuDataItem ...@@ -42,7 +43,7 @@ const filterMenuData = (menuList: MenuDataItem[], locale: boolean): MenuDataItem
}; };
const BasicLayout: React.FC<BasicLayoutProps> = props => { const BasicLayout: React.FC<BasicLayoutProps> = props => {
const { dispatch, children, settings } = props; const { dispatch, children, settings, location } = props;
/** /**
* constructor * constructor
*/ */
...@@ -73,6 +74,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => { ...@@ -73,6 +74,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
> >
{children} {children}
</BasicLayoutComponents> </BasicLayoutComponents>
{ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' && (
<SettingDrawer <SettingDrawer
settings={settings} settings={settings}
onSettingChange={config => onSettingChange={config =>
...@@ -82,6 +84,8 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => { ...@@ -82,6 +84,8 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
}) })
} }
/> />
)}
<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