ant migrate v4

pull/289/head
vapao 2020-11-24 17:14:44 +08:00
parent f21ce3f241
commit f13efa91cc
10 changed files with 222 additions and 232 deletions

View File

@ -3,13 +3,9 @@
* Copyright (c) <spug.dev@gmail.com>
* Released under the AGPL-3.0 License.
*/
const {override, fixBabelImports, addDecoratorsLegacy} = require('customize-cra');
const {override, addDecoratorsLegacy, addLessLoader} = require('customize-cra');
module.exports = override(
addDecoratorsLegacy(),
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
})
addLessLoader(),
);

View File

@ -1,24 +1,23 @@
{
"name": "spug_web",
"version": "0.1.0",
"version": "3.0.0",
"private": true,
"dependencies": {
"@antv/data-set": "^0.10.2",
"@ant-design/icons": "^4.3.0",
"ace-builds": "^1.4.7",
"antd": "^3.25.0",
"axios": "^0.19.0",
"antd": "^4.8.5",
"axios": "^0.20.0",
"bizcharts": "^3.5.6",
"history": "^4.10.1",
"http-proxy-middleware": "^0.20.0",
"lodash": "^4.17.19",
"mobx": "^5.15.0",
"mobx-react": "^6.1.4",
"mobx": "^5.15.6",
"mobx-react": "^6.3.0",
"moment": "^2.24.0",
"react": "^16.11.0",
"react": "^16.13.1",
"react-ace": "^8.0.0",
"react-dom": "^16.11.0",
"react-router-dom": "^5.1.2",
"react-scripts": "3.2.0",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3",
"xterm": "^4.6.0",
"xterm-addon-fit": "^0.4.0"
},
@ -44,9 +43,10 @@
]
},
"devDependencies": {
"@babel/plugin-proposal-decorators": "^7.7.0",
"babel-plugin-import": "^1.12.2",
"customize-cra": "^0.8.0",
"react-app-rewired": "^2.1.5"
"@babel/plugin-proposal-decorators": "^7.10.5",
"customize-cra": "^1.0.0",
"less": "^3.12.2",
"less-loader": "^7.1.0",
"react-app-rewired": "^2.1.6"
}
}

View File

@ -4,8 +4,9 @@
* Released under the AGPL-3.0 License.
*/
import React from 'react';
import { Layout, Icon } from 'antd';
import styles from './layout.module.css';
import { Layout } from 'antd';
import { CopyrightOutlined, GithubOutlined } from '@ant-design/icons';
import styles from './layout.module.less';
export default class extends React.Component {
@ -14,15 +15,15 @@ export default class extends React.Component {
<Layout.Footer style={{padding: 0}}>
<div className={styles.footerZone}>
<div className={styles.linksZone}>
<a className={styles.links} title="官网" href="https://www.spug.dev" target="_blank"
<a className={styles.links} title="官网" href="https://www.spug.dev" target="_blank"
rel="noopener noreferrer">官网</a>
<a className={styles.links} title="Github" href="https://github.com/openspug/spug" target="_blank"
rel="noopener noreferrer"><Icon type="github" /></a>
<a title="文档" href="https://www.spug.dev/docs/about-spug/" target="_blank"
<a className={styles.links} title="Github" href="https://github.com/openspug/spug" target="_blank"
rel="noopener noreferrer"><GithubOutlined/></a>
<a title="文档" href="https://www.spug.dev/docs/about-spug/" target="_blank"
rel="noopener noreferrer">文档</a>
</div>
<div style={{color: 'rgba(0, 0, 0, .45)'}}>
Copyright <Icon type="copyright"/> 2020 By OpenSpug
Copyright <CopyrightOutlined/> 2020 By OpenSpug
</div>
</div>
</Layout.Footer>

View File

@ -5,8 +5,16 @@
*/
import React from 'react';
import { Link } from 'react-router-dom';
import { Layout, Dropdown, Menu, List, Icon, Badge, Avatar } from 'antd';
import styles from './layout.module.css';
import { Layout, Dropdown, Menu, List, Badge, Avatar } from 'antd';
import {
CheckOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
UserOutlined,
LogoutOutlined,
NotificationOutlined
} from '@ant-design/icons';
import styles from './layout.module.less';
import http from '../libs/http';
import history from '../libs/history';
import avatar from './avatar.png';
@ -62,12 +70,12 @@ export default class extends React.Component {
<Menu>
<Menu.Item>
<Link to="/welcome/info">
<Icon type="user" style={{marginRight: 10}}/>个人中心
<UserOutlined style={{marginRight: 10}}/>个人中心
</Link>
</Menu.Item>
<Menu.Divider/>
<Menu.Item onClick={this.handleLogout}>
<Icon type="logout" style={{marginRight: 10}}/>退出登录
<LogoutOutlined style={{marginRight: 10}}/>退出登录
</Menu.Item>
</Menu>
);
@ -84,7 +92,7 @@ export default class extends React.Component {
<List.Item className={styles.notifyItem} onClick={e => this.handleRead(e, item)}>
<List.Item.Meta
style={{opacity: this.state.read.includes(item.id) ? 0.4 : 1}}
avatar={<Icon type={item.source} style={{fontSize: 24, color: '#1890ff'}}/>}
avatar={<CheckOutlined type={item.source} style={{fontSize: 24, color: '#1890ff'}}/>}
title={<span style={{fontWeight: 400, color: '#404040'}}>{item.title}</span>}
description={[
<div key="1" style={{fontSize: 12}}>{item.content}</div>,
@ -105,7 +113,7 @@ export default class extends React.Component {
<Layout.Header style={{padding: 0}}>
<div className={styles.header}>
<div className={styles.trigger} onClick={this.props.toggle}>
<Icon type={this.props.collapsed ? 'menu-unfold' : 'menu-fold'}/>
{this.props.collapsed ? <MenuUnfoldOutlined/> : <MenuFoldOutlined/>}
</div>
<div className={styles.right}>
<Dropdown overlay={this.menu}>
@ -119,7 +127,7 @@ export default class extends React.Component {
<Dropdown overlay={this.notify} trigger={['click']}>
<span className={styles.trigger}>
<Badge count={notifies.length - read.length}>
<Icon type="notification" style={{fontSize: 16}}/>
<NotificationOutlined style={{fontSize: 16}}/>
</Badge>
</span>
</Dropdown>

View File

@ -1,98 +1,64 @@
/**
* Copyright (c) OpenSpug Organization. https://github.com/openspug/spug
* Copyright (c) <spug.dev@gmail.com>
* Released under the AGPL-3.0 License.
*/
import React from 'react';
import { withRouter } from 'react-router-dom';
import { Layout, Menu, Icon } from 'antd';
import { hasPermission } from "../libs/functools";
import history from '../libs/history';
import { Layout, Menu } from 'antd';
import { hasPermission, history } from 'libs';
import styles from './layout.module.css';
import lodash from 'lodash';
import menus from '../menus';
import menus from '../routes';
import logo from './logo-spug.png';
import logoText from './logo-text.png';
class Sider extends React.Component {
constructor(props) {
super(props);
this._init(props);
this.state = {
selectedKeys: [],
openKeys: [lodash.get(this.keysMap, props.location.pathname)],
};
}
_init() {
this.keysMap = {};
for (let item of menus.filter(x => x.child)) {
for (let m of item.child) {
this.keysMap[m.path] = item.title
const initPath = window.location.pathname;
let openKeys = [];
loop:
for (let item of menus.filter(x => x.child)) {
for (let sub of item.child) {
if (sub.path === initPath) {
openKeys = [item.title]
break loop
}
}
}
UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.collapsed && !this.props.collapsed) {
this.setState({openKeys: []})
}
export default function Sider(props) {
function makeMenu(menu) {
if (menu.auth && !hasPermission(menu.auth)) return null;
if (!menu.title) return null;
return menu.child ? _makeSubMenu(menu) : _makeItem(menu)
}
makeMenu = (menu) => {
if (menu.auth !== undefined && !hasPermission(menu.auth)) return null;
return (menu.child) ? this.makeSubMenu(menu) : this.makeItem(menu)
};
function _makeSubMenu(menu) {
return (
<Menu.SubMenu key={menu.title} title={<span>{menu.icon}<span>{menu.title}</span></span>}>
{menu.child.map(menu => makeMenu(menu))}
</Menu.SubMenu>
)
}
makeItem = (menu) => {
function _makeItem(menu) {
return (
<Menu.Item key={menu.path}>
{menu.icon && <Icon type={menu.icon}/>}
{menu.icon}
<span>{menu.title}</span>
</Menu.Item>
)
};
}
makeSubMenu = (subMenu) => {
return (
<Menu.SubMenu key={subMenu.title} title={<span><Icon type={subMenu.icon}/><span>{subMenu.title}</span></span>}>
{subMenu.child.map(menu => this.makeMenu(menu))}
</Menu.SubMenu>
)
};
handleSelect = ({key}) => {
history.push(key)
};
handleClick = ({key}) => {
if (key === this.state.selectedKeys[0] && key !== this.props.location.pathname) {
this.props.history.push(key)
}
};
render() {
return (
<Layout.Sider collapsed={this.props.collapsed} style={{height: '100vh', overflow: 'scroll'}}>
<div className={styles.logo}>
<img src={logo} alt="Logo"/>
<img src={logoText} alt="logo-text" style={{marginLeft: 25, width: 70}} />
</div>
return (
<Layout.Sider width={208} collapsed={props.collapsed} className={styles.sider}>
<div className={styles.logo}>
<img src={logo} alt="Logo"/>
<img src={logoText} alt="logo-text" style={{marginLeft: 25, width: 70}}/>
</div>
<div className={styles.menus} style={{height: `${document.body.clientHeight - 64}px`}}>
<Menu
theme="dark"
mode="inline"
selectedKeys={[this.props.location.pathname]}
openKeys={this.state.openKeys}
onSelect={this.handleSelect}
onClick={this.handleClick}
onOpenChange={openKeys => this.setState({openKeys})}
>
{menus.map(menu => this.makeMenu(menu))}
className={styles.menus}
defaultSelectedKeys={[initPath]}
defaultOpenKeys={openKeys}
onSelect={menu => history.push(menu.key)}>
{menus.map(menu => makeMenu(menu))}
</Menu>
</Layout.Sider>
)
}
}
export default withRouter(Sider)
</div>
</Layout.Sider>
)
}

View File

@ -1,108 +0,0 @@
.header {
height: 64px;
padding: 0 12px 0 0;
background: #fff;
box-shadow: 2px 2px 2px rgba(0, 21, 41, 0.08);
position: relative;
z-index: 2;
}
.header .icon {
margin-right: 10px;
}
.content {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 24px 24px 0;
overflow-y: scroll;
}
.trigger {
font-size: 20px;
line-height: 64px;
cursor: pointer;
transition: all 0.3s, padding 0s;
padding: 0 24px;
float: left;
}
.trigger:hover {
background: rgb(233, 247, 254);
}
.logo {
height: 64px;
line-height: 64px;
padding-left: 15px;
overflow: hidden;
}
.logo h1 {
display: inline-block;
vertical-align: middle;
color: #ffffff;
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 20px;
margin: 0 0 0 12px;
font-weight: 600;
}
.logo img {
width: 50px;
}
.right {
float: right;
height: 100%;
}
.action {
cursor: pointer;
padding: 0 12px;
display: inline-block;
transition: all 0.3s;
height: 100%;
}
.action:hover {
background: rgb(233, 247, 254);
}
.notify {
width: 350px;
padding: 0;
}
.notify :global(.ant-dropdown-menu-item:hover) {
background-color: #fff;
}
.notifyItem {
align-items: center;
cursor: pointer;
padding: 12px 24px;
}
.notifyItem:hover {
background-color: rgb(233, 247, 254);
}
.notifyFooter {
line-height: 46px;
text-align: center;
cursor: pointer;
border-top: 1px solid #e8e8e8;
}
.footerZone {
width: 100%;
padding: 20px;
font-size: 14px;
text-align: center;
display: flex;
flex-direction: column;
}
.footerZone .linksZone {
margin-bottom: 7px;
}
.footerZone .links{
margin-right: 40px;
}

View File

@ -0,0 +1,124 @@
.header {
display: flex;
flex-direction: row;
padding: 0 12px 0 0;;
height: 48px;
line-height: 48px;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
z-index: 2;
.left {
flex: 1;
.trigger {
font-size: 20px;
line-height: 48px;
cursor: pointer;
transition: all 0.3s, padding 0s;
padding: 0 24px;
float: left;
}
.trigger:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.right {
.action {
cursor: pointer;
padding: 0 12px;
display: inline-block;
transition: all 0.3s;
height: 100%;
}
.action:hover {
background: rgba(0, 0, 0, 0.025);
}
}
}
.content {
padding: 24px 24px 0;
overflow-y: scroll;
}
.sider {
height: 100%;
width: 208px;
min-height: 100vh;
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
overflow: hidden;
.menus {
overflow: auto;
}
.logo {
height: 64px;
line-height: 64px;
padding-left: 24px;
background-color: #002140;
overflow: hidden;
}
.logo h1 {
display: inline-block;
vertical-align: middle;
color: #ffffff;
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 20px;
margin: 0 0 0 12px;
font-weight: 600;
}
.logo img {
height: 32px;
}
}
.footer {
margin: 48px 0 24px;
text-align: center;
color: rgba(0, 0, 0, .45);
}
.router {
display: flex;
height: 80%;
align-items: center;
.imgBlock {
flex: 0 0 62.5%;
width: 62.5%;
zoom: 1;
padding-right: 88px;
.img {
float: right;
height: 360px;
width: 100%;
max-width: 430px;
background-size: contain;
background: url('./404.svg') no-repeat 50% 50%;
}
}
.title {
color: #434e59;
font-size: 72px;
font-weight: 600;
line-height: 72px;
margin-bottom: 24px;
}
.desc {
color: rgba(0, 0, 0, .45);
font-size: 20px;
line-height: 28px;
margin-bottom: 16px;
}
}

View File

@ -5,7 +5,8 @@
*/
import React from 'react';
import { observer } from 'mobx-react';
import { Menu, Input, Button, Select, PageHeader, Icon, Modal } from 'antd';
import { Menu, Input, Button, Select, PageHeader, Modal } from 'antd';
import { TableOutlined, UnorderedListOutlined, NumberOutlined } from '@ant-design/icons';
import envStore from '../environment/store';
import styles from './index.module.css';
import history from 'libs/history';
@ -84,9 +85,9 @@ class Index extends React.Component {
<SearchForm>
<SearchForm.Item span={6} title="视图">
<Select value={view} style={{width: '100%'}} onChange={v => this.setState({view: v})}>
<Select.Option value="1"><Icon type="table" style={{marginRight: 10}}/>表格</Select.Option>
<Select.Option value="2"><Icon type="unordered-list" style={{marginRight: 10}}/>文本</Select.Option>
<Select.Option value="3"><Icon type="number" style={{marginRight: 10}}/>JSON</Select.Option>
<Select.Option value="1"><TableOutlined style={{marginRight: 10}}/>表格</Select.Option>
<Select.Option value="2"><UnorderedListOutlined style={{marginRight: 10}}/>文本</Select.Option>
<Select.Option value="3"><NumberOutlined style={{marginRight: 10}}/>JSON</Select.Option>
</Select>
</SearchForm.Item>
<SearchForm.Item span={7} title="Key">

View File

@ -4,7 +4,8 @@
* Released under the AGPL-3.0 License.
*/
import React from 'react';
import { Form, Input, Icon, Button, Tabs, Modal } from 'antd';
import { Form, Input, Button, Tabs, Modal } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import styles from './login.module.css';
import history from 'libs/history';
import { http, updatePermissions } from 'libs';
@ -94,7 +95,7 @@ class LoginIndex extends React.Component {
size="large"
autoComplete="off"
placeholder="请输入账户"
prefix={<Icon type="user" className={styles.icon}/>}/>
prefix={<UserOutlined className={styles.icon}/>}/>
)}
</Form.Item>
<Form.Item className={styles.formItem}>
@ -105,7 +106,7 @@ class LoginIndex extends React.Component {
autoComplete="off"
placeholder="请输入密码"
onPressEnter={this.handleSubmit}
prefix={<Icon type="lock" className={styles.icon}/>}/>
prefix={<LockOutlined className={styles.icon}/>}/>
)}
</Form.Item>
</Form>

View File

@ -4,7 +4,8 @@
* Released under the AGPL-3.0 License.
*/
import React from 'react';
import { Drawer, Breadcrumb, Table, Icon, Divider, Switch, Button, Progress, Modal, message } from 'antd';
import { Drawer, Breadcrumb, Table, Divider, Switch, Button, Progress, Modal, message } from 'antd';
import { DownloadOutlined, FileOutlined, FolderOutlined, DeleteOutlined, HomeOutlined } from '@ant-design/icons';
import { http, uniqueId, X_TOKEN } from 'libs';
import lds from 'lodash';
import styles from './index.module.css'
@ -31,12 +32,12 @@ class FileManager extends React.Component {
key: 'name',
render: info => info.kind === 'd' ? (
<div onClick={() => this.handleChdir(info.name, '1')} style={{cursor: 'pointer'}}>
<Icon type="folder" style={{color: '#1890ff'}}/>
<FolderOutlined style={{color: '#1890ff'}}/>
<span style={{color: '#1890ff', paddingLeft: 5}}>{info.name}</span>
</div>
) : (
<React.Fragment>
<Icon type="file"/>
<FileOutlined/>
<span style={{paddingLeft: 5}}>{info.name}</span>
</React.Fragment>
),
@ -63,9 +64,9 @@ class FileManager extends React.Component {
key: 'action',
render: info => info.kind === '-' ? (
<React.Fragment>
<Icon style={{color: '#1890ff'}} type="download" onClick={() => this.handleDownload(info.name)}/>
<DownloadOutlined style={{color: '#1890ff'}} onClick={() => this.handleDownload(info.name)}/>
<Divider type="vertical"/>
<Icon style={{color: 'red'}} type="delete" onClick={() => this.handleDelete(info.name)}/>
<DeleteOutlined style={{color: 'red'}} onClick={() => this.handleDelete(info.name)}/>
</React.Fragment>
) : null
}];
@ -188,7 +189,7 @@ class FileManager extends React.Component {
<div className={styles.drawerHeader}>
<Breadcrumb>
<Breadcrumb.Item href="#" onClick={() => this.handleChdir('', '0')}>
<Icon type="home"/>
<HomeOutlined/>
</Breadcrumb.Item>
{this.state.pwd.map(item => (
<Breadcrumb.Item key={item} href="#" onClick={() => this.handleChdir(item, '2')}>