├── src ├── pages │ ├── B │ │ ├── Status.less │ │ └── B.js │ ├── Main │ │ ├── Main.less │ │ └── Main.js │ └── A │ │ └── A.js ├── store │ ├── store.js │ └── loading_store.js ├── styles │ ├── common │ │ ├── common.less │ │ ├── utils.less │ │ └── reset.less │ └── theme │ │ ├── index.less │ │ └── variables.less ├── App.js ├── router │ ├── router_lazyload.js │ └── router.js ├── components │ ├── Header │ │ ├── Header.less │ │ └── Header.js │ ├── Loading │ │ ├── Loading.js │ │ └── Loading.less │ ├── Skin │ │ ├── Skin.less │ │ └── Skin.js │ └── Aside │ │ ├── Aside.less │ │ └── Aside.js ├── index.js └── utils │ └── usePlugin │ ├── utils.js │ └── axios.js ├── dist ├── static │ ├── font │ │ ├── iconfont.eot │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ ├── css │ │ ├── 2.css │ │ ├── main.css │ │ └── vendors.css │ └── js │ │ ├── 3.bundle.js │ │ ├── 2.bundle.js │ │ └── main.bundle.js ├── index.html └── dll │ └── vendor.mainfist.json ├── README.md ├── .gitignore ├── public └── index.html ├── webpack.config.dev.js ├── webpack.config.dll.js ├── webpack.config.prod.js ├── package.json └── webpack.config.common.js /src/pages/B/Status.less: -------------------------------------------------------------------------------- 1 | @import '../../styles/theme/index.less'; 2 | 3 | .asd{ 4 | background:#000 5 | } -------------------------------------------------------------------------------- /src/store/store.js: -------------------------------------------------------------------------------- 1 | import loadingStore from './loading_store' 2 | 3 | export default { 4 | loadingStore 5 | } -------------------------------------------------------------------------------- /dist/static/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xw-Zhou/webpack-optimizeDemo/HEAD/dist/static/font/iconfont.eot -------------------------------------------------------------------------------- /dist/static/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xw-Zhou/webpack-optimizeDemo/HEAD/dist/static/font/iconfont.ttf -------------------------------------------------------------------------------- /dist/static/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xw-Zhou/webpack-optimizeDemo/HEAD/dist/static/font/iconfont.woff -------------------------------------------------------------------------------- /src/styles/common/common.less: -------------------------------------------------------------------------------- 1 | @import './reset.less'; 2 | 3 | html,body{ 4 | height: 100%; 5 | } 6 | 7 | ::selection{ 8 | background: #1890ff!important; 9 | color:#fff!important; 10 | } -------------------------------------------------------------------------------- /src/pages/Main/Main.less: -------------------------------------------------------------------------------- 1 | 2 | .contentWrap{ 3 | background: #eee; 4 | padding:20px; 5 | min-height: calc(100vh - 70px); 6 | } 7 | .content{ 8 | background:#fff; 9 | border-radius:5px; 10 | padding:15px; 11 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## webpack优化DEMO 2 | 3 | 怎么运行? 4 | ``` 5 | yarn install 6 | yarn run dll //注意这里的顺序别弄错了,yarn run dll需要先执行 7 | yarn run dev 8 | ``` 9 | 10 | demo里的antd更换皮肤功能在打包==yarn run build==之后需要放在服务器上才会生效,直接==yarn run dev==也可以生效 11 | 12 | 13 | ps:demo写的比较粗糙,请见谅 14 | -------------------------------------------------------------------------------- /dist/static/css/2.css: -------------------------------------------------------------------------------- 1 | .primary-bg{background-color:#6064f4}.major-fontColor{color:#3531a8}.minor-fontColor{color:#6064f4}.major-borderTop{border-top:1px solid #6064f4}.major-borderBottom{border-bottom:1px solid #6064f4}.minor-borderTop{border-top:1px solid #dee2ff}.minor-borderBottom{border-bottom:1px solid #dee2ff}.asd{background:#000} -------------------------------------------------------------------------------- /src/pages/A/A.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | 3 | class A extends Component { 4 | constructor(props) { 5 | super(props) 6 | } 7 | 8 | render() { 9 | return ( 10 |
11 | aaa 12 |
13 | ) 14 | } 15 | } 16 | 17 | export default A -------------------------------------------------------------------------------- /src/styles/common/utils.less: -------------------------------------------------------------------------------- 1 | .show{ 2 | display: block!important; 3 | } 4 | .hide{ 5 | display: none!important; 6 | } 7 | 8 | @keyframes bounce-up { 9 | 25% { 10 | transform: translateY(-3px); 11 | } 12 | 50%, 100% { 13 | transform: translateY(1px); 14 | } 15 | 75% { 16 | transform: translateY(-3px); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/pages/B/B.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | 3 | import './Status.less' 4 | 5 | class Status extends Component { 6 | constructor(props) { 7 | super(props) 8 | } 9 | 10 | render() { 11 | return ( 12 |
13 | bbbb 14 |
15 | ) 16 | } 17 | } 18 | 19 | export default Status -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | 3 | 4 | class App extends Component { 5 | constructor(props) { 6 | super(props) 7 | this.state = {} 8 | } 9 | 10 | render() { 11 | return ( 12 |
13 | {this.props.children} 14 |
15 | ) 16 | } 17 | } 18 | 19 | export default App -------------------------------------------------------------------------------- /src/router/router_lazyload.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Loadable from 'react-loadable'; 3 | 4 | const A = Loadable({ 5 | loader: () => import('../pages/A/A'), 6 | loading:()=>
loading...
7 | }); 8 | const B = Loadable({ 9 | loader: () => import('../pages/B/B'), 10 | loading:()=>
loading...
11 | }); 12 | 13 | 14 | export { 15 | A,B 16 | } -------------------------------------------------------------------------------- /dist/static/js/3.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[3],{154:function(n,e,t){"use strict";t.r(e);var r=t(10),u=t.n(r),a=t(11),i=t.n(a),o=t(13),c=t.n(o),s=t(14),l=t.n(s),p=t(15),w=t.n(p),d=t(1),f=t.n(d),h=function(n){function e(n){return u()(this,e),c()(this,l()(e).call(this,n))}return w()(e,n),i()(e,[{key:"render",value:function(){return f.a.createElement("div",null,"aaa")}}]),e}(d.Component);e.default=h}}]); -------------------------------------------------------------------------------- /src/store/loading_store.js: -------------------------------------------------------------------------------- 1 | import {observable,computed,action} from 'mobx' 2 | 3 | 4 | class loading_store{ 5 | @observable show=false 6 | 7 | @action ajaxStart(){ 8 | this.show=true 9 | } 10 | 11 | @action ajaxEnd(wait=0){ 12 | setTimeout(()=>{ 13 | this.show=false 14 | },wait) 15 | } 16 | } 17 | 18 | const loadingStore=new loading_store(); 19 | 20 | export default loadingStore -------------------------------------------------------------------------------- /dist/static/js/2.bundle.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[2],{153:function(n,t,e){},155:function(n,t,e){"use strict";e.r(t);var u=e(10),i=e.n(u),r=e(11),o=e.n(r),c=e(13),a=e.n(c),s=e(14),l=e.n(s),b=e(15),f=e.n(b),p=e(1),w=e.n(p),d=(e(153),function(n){function t(n){return i()(this,t),a()(this,l()(t).call(this,n))}return f()(t,n),o()(t,[{key:"render",value:function(){return w.a.createElement("div",null,"bbbb")}}]),t}(p.Component));t.default=d}}]); -------------------------------------------------------------------------------- /src/components/Header/Header.less: -------------------------------------------------------------------------------- 1 | @import '../../styles/theme/index.less'; 2 | 3 | .header{ 4 | height:70px; 5 | width:100%; 6 | box-shadow: 0 3px 10px #ccc; 7 | position: relative; 8 | z-index: 3; 9 | >a{ 10 | height:60px; 11 | width:180px; 12 | margin-left:20px; 13 | display: inline-block; 14 | position: absolute; 15 | top:50%; 16 | transform: translateY(-50%); 17 | img{ 18 | width:100%; 19 | height:100%; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/Header/Header.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import Skin from 'components/Skin/Skin' 3 | 4 | import './Header.less' 5 | 6 | class Header extends Component { 7 | constructor(props) { 8 | super(props) 9 | this.state = {} 10 | } 11 | componentDidMount(){ 12 | 13 | } 14 | render() { 15 | return ( 16 |
17 | 18 |
19 | ) 20 | } 21 | } 22 | 23 | export default Header -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | #* 3 | /__MACOSX 4 | 5 | # history 6 | /.history 7 | 8 | # dependencies 9 | /node_modules 10 | /.pnp 11 | .pnp.js 12 | 13 | # testing 14 | /coverage 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | .env.local 22 | .env.development.local 23 | .env.test.local 24 | .env.production.local 25 | 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | #vscode 31 | .vscode 32 | 33 | #yarn 34 | 35 | #docz 36 | .docz 37 | 38 | .idea 39 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import "@babel/polyfill" 2 | import 'es6-proxy-polyfill'//用来兼容mobx 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import Routers from './router/router' 6 | import { HashRouter as Router, } from 'react-router-dom' 7 | import {Provider} from 'mobx-react' 8 | 9 | 10 | import './styles/common/common.less' 11 | 12 | 13 | if (module.hot) { 14 | module.hot.accept() 15 | } 16 | 17 | ReactDOM.render( 18 | 19 | 20 | 21 | 22 | 23 | ,document.getElementById('root')); -------------------------------------------------------------------------------- /src/styles/theme/index.less: -------------------------------------------------------------------------------- 1 | @import 'variables'; 2 | 3 | 4 | //自己定义的主题颜色 5 | .primary-bg{//公用的背景颜色,主色为@primary-6 6 | background-color:@primary-color; 7 | } 8 | 9 | .major-fontColor{//主要的文字颜色:标题等 10 | color:@primary-8; 11 | } 12 | 13 | .minor-fontColor{//次要的文字颜色 14 | color:@primary-color; 15 | } 16 | 17 | .major-borderTop{//主要的上边框 18 | border-top:1px solid @primary-color; 19 | } 20 | 21 | .major-borderBottom{//主要的下边框 22 | border-bottom:1px solid @primary-color; 23 | } 24 | 25 | .minor-borderTop{//次要的上边框,透明度为主色的30% 26 | border-top:1px solid @primary-3; 27 | } 28 | 29 | .minor-borderBottom{//次要的下边框 30 | border-bottom:1px solid @primary-3; 31 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | React 7 | 8 | 9 | 10 | 16 |
17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const path=require('path'); 2 | const webpack=require('webpack'); 3 | const merge=require('webpack-merge'); 4 | const common=require('./webpack.config.common.js'); 5 | 6 | module.exports=merge(common,{ 7 | mode:'development', 8 | devtool:'cheap-module-eval-source-map', 9 | module:{ 10 | rules:[ 11 | 12 | ] 13 | }, 14 | devServer: { 15 | contentBase: path.join(__dirname, "dist"), 16 | compress: true,//开启gzip压缩 17 | port: 8080, 18 | open:true, 19 | //progress:true,//显示进度条 20 | hot:true, 21 | overlay:true,//错误显示在浏览器上 22 | //historyApiFallback:true//当访问的路径为404的时候跳转 23 | }, 24 | plugins:[ 25 | new webpack.HotModuleReplacementPlugin(), 26 | ] 27 | }) -------------------------------------------------------------------------------- /src/styles/common/reset.less: -------------------------------------------------------------------------------- 1 | html {overflow-y:scroll;} 2 | body {margin:0; padding:0; font:12px Arial,sans-serif;/*background:#ffffff;*/} 3 | div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,blockquote,p{padding:0; margin:0;} 4 | table,td,tr,th{font-size:12px;} 5 | ol,ul {list-style:none;} 6 | li{list-style-type:none;} 7 | img{vertical-align:top;border:0;} 8 | h1,h2,h3,h4,h5,h6{font-size:inherit; font-weight:normal;} 9 | address,cite,code,em,th,i{font-weight:normal; font-style:normal;} 10 | .hx a,.hx em,.fB{font-weight:bold;} 11 | .clearfix{*zoom:1;} 12 | .clearfix:after{display:block; overflow:hidden; clear:both; height:0; visibility:hidden; content:".";} 13 | a {color:#252525; text-decoration:none;} 14 | a:visited {text-decoration:none;} 15 | a:hover {text-decoration:none;} 16 | -------------------------------------------------------------------------------- /src/components/Loading/Loading.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | 3 | import './Loading.less' 4 | 5 | class App extends Component { 6 | constructor(props) { 7 | super(props) 8 | this.state = {} 9 | } 10 | 11 | render() { 12 | return ( 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ) 23 | } 24 | } 25 | 26 | export default App -------------------------------------------------------------------------------- /src/styles/theme/variables.less: -------------------------------------------------------------------------------- 1 | @import "~antd/lib/style/themes/default.less"; 2 | //这里是在没有设置window.less.modifyVars的时候显示的默认颜色 3 | 4 | 5 | @primary-color: #6064f4; 6 | //@text-color: #000000; 7 | //@text-color-secondary: #eb2f96; 8 | //@heading-color: #ccccdd; 9 | //@layout-header-background: #b36e94; 10 | //@btn-primary-bg: #ccc849; 11 | //@bg-color: #dddddd; 12 | 13 | 14 | 15 | 16 | 17 | //window.less.modifyVars( 18 | // { 19 | // '@primary-color': '#000', 20 | // '@secondary-color': '#0000ff', 21 | // '@text-color': '#000000', 22 | // '@text-color-secondary': '#eb2f96', 23 | // '@heading-color': '#fa8c16', 24 | // '@layout-header-background': '#b36e94', 25 | // '@btn-primary-bg': '#ccc' 26 | // } 27 | //) 28 | //.then(() => {console.log('success')}) 29 | //.catch(error => { 30 | //console.log('error'); 31 | //}); -------------------------------------------------------------------------------- /webpack.config.dll.js: -------------------------------------------------------------------------------- 1 | const path=require('path') 2 | const webpack =require('webpack') 3 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 4 | 5 | //只需要使用yarn run dll一次就行 6 | module.exports={ 7 | mode:'production', 8 | entry:{ 9 | vendor:[//'@ant-design/icons/lib/dist.js' 10 | '@babel/polyfill', 11 | 'react', 12 | 'react-dom', 13 | 'react-router-dom', 14 | 'mobx', 15 | 'mobx-react' 16 | ], 17 | }, 18 | output:{ 19 | filename:'dll/_dll_[name].js', 20 | path:path.resolve(__dirname,'dist'), 21 | library:'_dll_[name]' 22 | }, 23 | plugins:[ 24 | new webpack.DllPlugin({ 25 | name:'_dll_[name]', 26 | path:path.resolve(__dirname,'dist/dll','[name].mainfist.json') 27 | }), 28 | new CleanWebpackPlugin(['./dist/dll']),//删除dll目录下的文件 29 | ] 30 | } -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | React 7 | 8 | 9 | 10 | 16 |
17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/router/router.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Router,Route,Switch,Redirect } from 'react-router-dom' 3 | import App from '../App' 4 | import Main from '../pages/Main/Main' 5 | import {A,B} from './router_lazyload' 6 | 7 | 8 | class Routers extends Component { 9 | constructor(props) { 10 | super(props); 11 | this.state = {} 12 | } 13 | componentDidMount(){ 14 | 15 | } 16 | render() { 17 | return ( 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 |
28 | }/> 29 |
30 |
31 | ); 32 | } 33 | } 34 | 35 | export default Routers; -------------------------------------------------------------------------------- /src/pages/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {Col,Row} from 'antd' 3 | import Aside from 'components/Aside/Aside' 4 | import Header from 'components/Header/Header' 5 | 6 | //less 7 | import './Main.less' 8 | 9 | class Main extends Component { 10 | constructor(props) { 11 | super(props) 12 | this.state = { 13 | loading_show:true 14 | } 15 | } 16 | 17 | render() { 18 | return ( 19 |
20 |
21 | 22 | 23 |
34 | ) 35 | } 36 | } 37 | 38 | export default Main -------------------------------------------------------------------------------- /webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | 2 | const merge = require('webpack-merge'); 3 | const path = require('path'); 4 | const webpack = require('webpack'); 5 | const common = require('./webpack.config.common.js'); 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 7 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 8 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); 9 | 10 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 11 | 12 | module.exports = merge(common, { 13 | mode: 'production', 14 | 15 | module: { 16 | rules: [ 17 | 18 | ] 19 | }, 20 | plugins: [ 21 | new MiniCssExtractPlugin({//提取css 22 | filename: 'static/css/[name].css' 23 | }), 24 | new CopyWebpackPlugin([{ 25 | from: path.resolve(__dirname, './public'), //定义要拷贝的源目录,必填项 26 | //to: path.resolve(__dirname, './dist/'), //定义要拷贝到的目标目录,非必填,不填写则拷贝到打包的output输出地址中 27 | }]), 28 | new CleanWebpackPlugin(['./static/']),//先删除dist/static目录下的文件,对我们来说只有这个目录和index.html改变的 29 | new BundleAnalyzerPlugin({ analyzerPort: 8090 }), 30 | ] 31 | }) -------------------------------------------------------------------------------- /src/components/Skin/Skin.less: -------------------------------------------------------------------------------- 1 | @import '../../styles/theme/index.less'; 2 | 3 | 4 | .skin-wrap{ 5 | position: absolute; 6 | right:0; 7 | top:0; 8 | box-shadow: 0 -5px 30px rgba(0,0,0,.2); 9 | height:100%; 10 | width:120px; 11 | box-sizing: border-box; 12 | .skin-root{ 13 | color: #fff; 14 | line-height: 70px; 15 | text-align: center; 16 | font-size:14px; 17 | user-select: none; 18 | &:hover{ 19 | cursor: pointer; 20 | } 21 | >i{ 22 | font-size:20px; 23 | } 24 | >span{ 25 | margin-left:5px; 26 | } 27 | } 28 | 29 | .skin-dropDown{ 30 | width:100%; 31 | background:#fff; 32 | opacity:0; 33 | position: relative; 34 | top:-10px; 35 | height:0; 36 | overflow: hidden; 37 | transition: top 0.2s,opacity 0.2s; 38 | box-shadow: 0 2px 40px rgba(0,0,0,.4); 39 | 40 | .change-theme{ 41 | display: flex; 42 | padding:10px; 43 | justify-content: space-between; 44 | flex-wrap: wrap; 45 | >li{ 46 | cursor: pointer; 47 | width:20px; 48 | height:20px; 49 | background: #000; 50 | margin:5px; 51 | } 52 | } 53 | 54 | .sign-out{ 55 | font-size:16px; 56 | padding:10px; 57 | text-align: center; 58 | >span{ 59 | cursor: pointer; 60 | } 61 | } 62 | 63 | } 64 | } -------------------------------------------------------------------------------- /src/components/Aside/Aside.less: -------------------------------------------------------------------------------- 1 | @import '../../styles/theme/index.less'; 2 | 3 | .aside{ 4 | box-sizing: border-box; 5 | height:calc(100vh - 70px); 6 | box-shadow: 3px 0 10px #ccc; 7 | position: relative; 8 | z-index: 2; 9 | padding:30px 0; 10 | overflow: hidden; 11 | &:hover{ 12 | overflow: auto; 13 | } 14 | li{ 15 | margin-bottom: 0 !important; 16 | margin-top: 0 !important; 17 | } 18 | li:hover{ 19 | background:#f9f9f9; 20 | } 21 | >ul>li:first-child{ 22 | border-top:none; 23 | } 24 | >ul>li:last-child{ 25 | border-bottom:1px solid #f3f3f3; 26 | } 27 | >ul>li{ 28 | border-top:1px solid #f3f3f3; 29 | } 30 | >ul>li>ul>li{ 31 | border-bottom:1px solid #f3f3f3; 32 | } 33 | >ul>li>ul>li:last-child{ 34 | border-bottom:none; 35 | } 36 | } 37 | .spans{ 38 | display: inline-block; 39 | font-weight: bold; 40 | border-radius:3px; 41 | text-align:center; 42 | float:right; 43 | margin-right:5px; 44 | } 45 | 46 | 47 | 48 | 49 | 50 | @media screen and (min-width: 576px){//如果文档宽度大于576px 51 | .asideFixed{ 52 | 53 | } 54 | } 55 | @media screen and (min-width: 768px){//如果文档宽度大于768px 56 | .asideFixed{ 57 | position: fixed; 58 | left:0; 59 | height:100vh; 60 | width:25%; 61 | } 62 | } 63 | @media screen and (min-width: 992px){//如果文档宽度大于992px 64 | .asideFixed{ 65 | position: fixed; 66 | left:0; 67 | height:100vh; 68 | width:16.66666667%; 69 | } 70 | } 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/utils/usePlugin/utils.js: -------------------------------------------------------------------------------- 1 | 2 | class Utils{ 3 | judgeDOM(dom,parent){//判断某元素是不是另外一个元素的子元素 4 | while (dom != undefined && dom != null && dom.tagName.toUpperCase() != 'BODY'){ 5 | if (dom == parent){ 6 | return true; 7 | } 8 | dom = dom.parentNode; 9 | } 10 | return false; 11 | } 12 | IsRealUrl(mockUrl='',realUrl='',flag=true){//判断是否真实的接口 13 | return flag ? mockUrl : realUrl 14 | } 15 | Typeof(res){ // 判断数据类型 16 | return toString.call(res).split(' ')[1].split(']')[0] 17 | } 18 | changeTableData(data,res){ //修改数据,往数据里添加需要的键,主要在表格上使用,res是需要添加的键,字符串类型 19 | let num=0; 20 | let arr=[]; 21 | let datas=JSON.parse(JSON.stringify(data)); 22 | 23 | for(let i in datas){ 24 | num++; 25 | datas[i][res]=num; 26 | arr.push(datas[i]) 27 | } 28 | return arr; 29 | } 30 | genSrcIdxKey(idx){ 31 | let decStr='',sixStr=''; 32 | 33 | if(parseInt(idx) < 16){ 34 | decStr = '0'; 35 | } 36 | decStr += idx.toString(16);//toString把一个逻辑值转换为字符串 37 | if(arguments.length>1){ 38 | if((parseInt(arguments[1])+1) < 16){ 39 | sixStr = '0'; 40 | } 41 | sixStr += (parseInt(arguments[1])+1).toString(16); 42 | }else{ 43 | sixStr='00'; 44 | } 45 | return ((sixStr.concat(decStr)).toString(16));//concat连接2个或多个数组 46 | } 47 | 48 | 49 | } 50 | 51 | let utils=new Utils(); 52 | 53 | export default utils; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "author": "ZXW", 7 | "scripts": { 8 | "build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js", 9 | "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js", 10 | "dll": "webpack --config webpack.config.dll.js" 11 | }, 12 | "devDependencies": { 13 | "@babel/core": "^7.2.2", 14 | "@babel/plugin-proposal-class-properties": "^7.3.4", 15 | "@babel/plugin-proposal-decorators": "^7.3.0", 16 | "@babel/plugin-transform-runtime": "^7.2.0", 17 | "@babel/preset-env": "^7.3.1", 18 | "@babel/preset-react": "^7.0.0", 19 | "antd": "3.8.2", 20 | "antd-theme-webpack-plugin": "^1.2.0", 21 | "autoprefixer": "^9.4.7", 22 | "axios": "^0.18.0", 23 | "babel-loader": "^8.0.5", 24 | "babel-plugin-equire": "^1.1.1", 25 | "babel-plugin-import": "^1.11.0", 26 | "babel-plugin-syntax-dynamic-import": "^6.18.0", 27 | "clean-webpack-plugin": "^1.0.1", 28 | "cross-env": "^5.2.0", 29 | "css-loader": "^2.1.0", 30 | "file-loader": "^3.0.1", 31 | "happypack": "^5.0.1", 32 | "html-webpack-plugin": "^3.2.0", 33 | "less": "^3.9.0", 34 | "less-loader": "^4.1.0", 35 | "mini-css-extract-plugin": "^0.5.0", 36 | "optimize-css-assets-webpack-plugin": "^5.0.1", 37 | "postcss-loader": "^3.0.0", 38 | "react": "^16.8.1", 39 | "react-dom": "^16.8.1", 40 | "react-loadable": "^5.5.0", 41 | "react-router-dom": "^4.3.1", 42 | "style-loader": "^0.23.1", 43 | "uglifyjs-webpack-plugin": "^2.1.1", 44 | "url-loader": "^1.1.2", 45 | "webpack": "^4.29.3", 46 | "webpack-bundle-analyzer": "^3.0.4", 47 | "webpack-cli": "^3.2.3", 48 | "webpack-dev-server": "^3.1.14", 49 | "webpack-merge": "^4.2.1" 50 | }, 51 | "dependencies": { 52 | "@babel/polyfill": "^7.2.5", 53 | "@babel/runtime": "^7.3.1", 54 | "antd-iconfont": "^3.0.3", 55 | "copy-webpack-plugin": "^5.0.5", 56 | "echarts": "^4.1.0", 57 | "es6-proxy-polyfill": "^1.2.1", 58 | "mobx": "^5.9.0", 59 | "mobx-react": "^5.4.3", 60 | "qs": "^6.6.0" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/components/Loading/Loading.less: -------------------------------------------------------------------------------- 1 | .loading-wrap{ 2 | position: fixed; 3 | top:0; 4 | left:0; 5 | right:0; 6 | bottom:0; 7 | background:rgba(0,0,0,.5); 8 | z-index:999; 9 | } 10 | .loading-container { 11 | width: 30px; 12 | height: 30px; 13 | position: relative; 14 | left:50%; 15 | top:50%; 16 | } 17 | .loading-container .shape { 18 | position: absolute; 19 | width: 10px; 20 | height: 10px; 21 | border-radius: 1px; 22 | } 23 | .loading-container .shape.shape1 { 24 | left: 0; 25 | background-color: #5C6BC0; 26 | } 27 | .loading-container .shape.shape2 { 28 | right: 0; 29 | background-color: #8BC34A; 30 | } 31 | .loading-container .shape.shape3 { 32 | bottom: 0; 33 | background-color: #FFB74D; 34 | } 35 | .loading-container .shape.shape4 { 36 | bottom: 0; 37 | right: 0; 38 | background-color: #F44336; 39 | } 40 | 41 | .loading-container.animation-2 { 42 | transform: rotate(10deg); 43 | } 44 | .loading-container.animation-2 .shape { 45 | border-radius: 5px; 46 | } 47 | .loading-container.animation-2 { 48 | animation: rotation 1s infinite; 49 | } 50 | @keyframes rotation { 51 | from { 52 | transform: rotate(0deg); 53 | } 54 | to { 55 | transform: rotate(360deg); 56 | } 57 | } 58 | 59 | .animation-2 .shape1 { 60 | animation: animation2shape1 0.5s ease 0s infinite alternate; 61 | } 62 | @keyframes animation2shape1 { 63 | from { 64 | transform: translate(0, 0); 65 | } 66 | to { 67 | transform: translate(20px, 20px); 68 | } 69 | } 70 | 71 | .animation-2 .shape2 { 72 | animation: animation2shape2 0.5s ease 0s infinite alternate; 73 | } 74 | @keyframes animation2shape2 { 75 | from { 76 | transform: translate(0, 0); 77 | } 78 | to { 79 | transform: translate(-20px, 20px); 80 | } 81 | } 82 | 83 | .animation-2 .shape3 { 84 | animation: animation2shape3 0.5s ease 0s infinite alternate; 85 | } 86 | @keyframes animation2shape3 { 87 | from { 88 | transform: translate(0, 0); 89 | } 90 | to { 91 | transform: translate(20px, -20px); 92 | } 93 | } 94 | 95 | .animation-2 .shape4 { 96 | animation: animation2shape4 0.5s ease 0s infinite alternate; 97 | } 98 | @keyframes animation2shape4 { 99 | from { 100 | transform: translate(0, 0); 101 | } 102 | to { 103 | transform: translate(-20px, -20px); 104 | } 105 | } 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/components/Aside/Aside.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {Menu,Icon} from 'antd' 3 | import {NavLink,withRouter} from 'react-router-dom' 4 | 5 | import './Aside.less' 6 | 7 | const SubMenu = Menu.SubMenu; 8 | 9 | const MenuConfig=[ 10 | { 11 | title:'AAA', 12 | key:'/a' 13 | }, 14 | { 15 | title:'BBB', 16 | key:'/b', 17 | }, 18 | ] 19 | 20 | class Aside extends Component { 21 | constructor(props) { 22 | super(props) 23 | this.state = { 24 | menuNode:'' 25 | } 26 | } 27 | componentWillMount(){ 28 | let menuNode=this.renderMenu(MenuConfig); 29 | this.setState({ 30 | menuNode 31 | }) 32 | } 33 | componentDidMount(){ 34 | this.windowScroll() 35 | } 36 | renderMenu=(data)=>{//渲染菜单栏 37 | return data.map((item,ind)=>{ 38 | if(item.children){//如果有子元素的话递归渲染 39 | return ( 40 | 41 | {this.renderMenu(item.children)} 42 | 43 | ) 44 | } 45 | return ( 46 | 47 | 48 | 49 | {item.title} 50 | 51 | 52 | ) 53 | }) 54 | } 55 | childrenNum=(Item)=>{//渲染下拉菜单的子节点个数 56 | let title=Item.title; 57 | let childLen=Item.children.length; 58 | return ( 59 | 60 | 61 | {title} 62 | {childLen} 63 | 64 | ) 65 | } 66 | handleOpen=(e)=>{//点击下拉菜单的子节点时触发 67 | // e.domEvent.persist(); 68 | // console.log(e.domEvent) 69 | } 70 | windowScroll=()=>{//设置aside的样式 71 | let asideDOM=this.asideDOM; 72 | let headerHeight=parseInt(getComputedStyle(document.getElementsByClassName('header')[0])['height']); 73 | 74 | window.addEventListener('scroll',function () { 75 | let contentTop=document.documentElement.scrollTop||document.body.scrollTop; 76 | let Top=headerHeight-contentTop < 0 ? 0 : headerHeight-contentTop; 77 | let screenWith=document.documentElement.offsetWidth || document.body.offsetWidth; 78 | // console.log(screenWith) 79 | if(screenWith<768){ 80 | asideDOM.style=""; 81 | }else if(screenWith>=768){ 82 | asideDOM.style.cssText=`top:${Top+'px'}`; 83 | } 84 | }) 85 | } 86 | render() { 87 | return ( 88 |
{this.asideDOM=e}}> 89 | 90 | {this.state.menuNode} 91 | 92 |
93 | ) 94 | } 95 | } 96 | 97 | export default withRouter(Aside) -------------------------------------------------------------------------------- /src/components/Skin/Skin.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {Icon} from 'antd' 3 | import utils from 'utils/usePlugin/utils' 4 | import {withRouter} from 'react-router-dom' 5 | 6 | import './Skin.less' 7 | 8 | class Skin extends Component { 9 | constructor(props) { 10 | super(props) 11 | this.state = { 12 | theme_list:['#405bff','#e57bee','#ff6130','#a9c0ff','#49aa4b','#8ba69c'] 13 | } 14 | // this.dropDown=React.createRef(); 15 | } 16 | componentDidMount(){ 17 | //页面打开保存上次设置的主题思路:将设置的颜色对象值传给后端,在compoentDidMount页面加载的时候去请求后端,然后在请求成功的then里执行 18 | } 19 | 20 | handleDropDown=(e)=>{//点击显示下拉菜单 21 | e.persist(); 22 | let dropDown=this.dropDown; 23 | dropDown.style.cssText="opacity:1;top:0px;height:auto;min-height:120px;"; 24 | document.body.addEventListener('click',this.judge) 25 | } 26 | 27 | judge=(e)=>{ 28 | e=e||window.event; 29 | let target=e.target||e.srcElement; 30 | let dropDown=this.dropDown; 31 | if(dropDown.style.opacity===0){return;} 32 | let flag=utils.judgeDOM(target,this.dropDown); 33 | if(!flag && dropDown){ 34 | dropDown.style.cssText="opacity:0;top:-10px;height:0"; 35 | } 36 | document.body.removeEventListener('click',this.judge); 37 | } 38 | 39 | themeList=(e)=>{//点击更换皮肤 40 | e=e||window.event; 41 | let target=e.target; 42 | let color; 43 | if(target.tagName.toLowerCase()==='li'){ 44 | color=target.getAttribute('data-theme'); 45 | window.less.modifyVars( 46 | { 47 | '@primary-color': color, 48 | // '@btn-primary-bg': '#cc753f', 49 | } 50 | ) 51 | .then(() => {console.log('success')}) 52 | .catch(error => { 53 | console.log(error); 54 | }); 55 | } 56 | // ref={(e)=>this.dropDown=e} 57 | } 58 | handleLoginOut=()=>{ 59 | this.props.history.push('/login') 60 | } 61 | render() { 62 | return ( 63 |
64 |
65 | 66 | Root User 67 |
68 |
    this.dropDown=e}> 69 |
  • 70 |
      71 | { 72 | this.state.theme_list.map((item,ind)=>{ 73 | return ( 74 |
    • 75 | ) 76 | }) 77 | } 78 |
    79 |
  • 80 |
  • 81 | Sign out 82 |
  • 83 |
84 |
85 | ) 86 | } 87 | } 88 | 89 | export default withRouter(Skin) -------------------------------------------------------------------------------- /dist/static/css/main.css: -------------------------------------------------------------------------------- 1 | .aside{-webkit-box-sizing:border-box;box-sizing:border-box;height:calc(100vh - 70px);-webkit-box-shadow:3px 0 10px #ccc;box-shadow:3px 0 10px #ccc;position:relative;z-index:2;padding:30px 0;overflow:hidden}.aside:hover{overflow:auto}.aside li{margin-bottom:0!important;margin-top:0!important}.aside li:hover{background:#f9f9f9}.aside>ul>li:first-child{border-top:none}.aside>ul>li:last-child{border-bottom:1px solid #f3f3f3}.aside>ul>li{border-top:1px solid #f3f3f3}.aside>ul>li>ul>li{border-bottom:1px solid #f3f3f3}.aside>ul>li>ul>li:last-child{border-bottom:none}.spans{display:inline-block;font-weight:700;border-radius:3px;text-align:center;float:right;margin-right:5px}@media screen and (min-width:768px){.asideFixed{position:fixed;left:0;height:100vh;width:25%}}@media screen and (min-width:992px){.asideFixed{position:fixed;left:0;height:100vh;width:16.66666667%}}.skin-wrap{position:absolute;right:0;top:0;-webkit-box-shadow:0 -5px 30px rgba(0,0,0,.2);box-shadow:0 -5px 30px rgba(0,0,0,.2);height:100%;width:120px;-webkit-box-sizing:border-box;box-sizing:border-box}.skin-wrap .skin-root{color:#fff;line-height:70px;text-align:center;font-size:14px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.skin-wrap .skin-root:hover{cursor:pointer}.skin-wrap .skin-root>i{font-size:20px}.skin-wrap .skin-root>span{margin-left:5px}.skin-wrap .skin-dropDown{width:100%;background:#fff;opacity:0;position:relative;top:-10px;height:0;overflow:hidden;-webkit-transition:top .2s,opacity .2s;transition:top .2s,opacity .2s;-webkit-box-shadow:0 2px 40px rgba(0,0,0,.4);box-shadow:0 2px 40px rgba(0,0,0,.4)}.skin-wrap .skin-dropDown .change-theme{display:-webkit-box;display:-ms-flexbox;display:flex;padding:10px;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-wrap:wrap;flex-wrap:wrap}.skin-wrap .skin-dropDown .change-theme>li{cursor:pointer;width:20px;height:20px;background:#000;margin:5px}.skin-wrap .skin-dropDown .sign-out{font-size:16px;padding:10px;text-align:center}.skin-wrap .skin-dropDown .sign-out>span{cursor:pointer}.primary-bg{background-color:#6064f4}.major-fontColor{color:#3531a8}.minor-fontColor{color:#6064f4}.major-borderTop{border-top:1px solid #6064f4}.major-borderBottom{border-bottom:1px solid #6064f4}.minor-borderTop{border-top:1px solid #dee2ff}.minor-borderBottom{border-bottom:1px solid #dee2ff}.header{height:70px;width:100%;-webkit-box-shadow:0 3px 10px #ccc;box-shadow:0 3px 10px #ccc;position:relative;z-index:3}.header>a{height:60px;width:180px;margin-left:20px;display:inline-block;position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.header>a img{width:100%;height:100%}.contentWrap{background:#eee;padding:20px;min-height:calc(100vh - 70px)}.content{background:#fff;border-radius:5px;padding:15px}html{overflow-y:scroll}body{font:12px Arial,sans-serif}blockquote,body,dd,div,dl,dt,fieldset,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,textarea,ul{margin:0;padding:0}table,td,th,tr{font-size:12px}ol,ul{list-style:none}li{list-style-type:none}img{vertical-align:top;border:0}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:400}address,cite,code,em,i,th{font-weight:400;font-style:normal}.fB,.hx a,.hx em{font-weight:700}.clearfix{*zoom:1}.clearfix:after{display:block;overflow:hidden;clear:both;height:0;visibility:hidden;content:"."}a{color:#252525}a,a:hover,a:visited{text-decoration:none}body,html{height:100%}::selection{background:#1890ff!important;color:#fff!important} -------------------------------------------------------------------------------- /src/utils/usePlugin/axios.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import qs from 'qs' 3 | import Store from 'store/store' 4 | import {message} from 'antd' 5 | import Utils from './utils' 6 | 7 | 8 | message.config({ 9 | top: '50%',//提示框据顶部距离 10 | duration: 2,//提示框持续时间 s 11 | }); 12 | let CancelToken=axios.CancelToken; 13 | let cancel=null; 14 | 15 | 16 | class Ajax { 17 | request(param) { 18 | axios.defaults.headers.common={ 19 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 20 | // 'Accept-Encoding': 'gzip, deflate' 21 | } 22 | const ajaxParam={ 23 | url: param.url || '',//请求地址 24 | method: param.method || 'post',//请求方法 25 | data: qs.stringify({json: JSON.stringify(param.data)}) || '',//发送的数据 26 | timeout: param.timeout || 30000,//设置请求超时 27 | responseType:param.responseType || 'json',//响应的数据格式 28 | headers: param.headers || {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},//请求头 29 | loadingNeed: param.loadingNeed===undefined ? true : param.loadingNeed,//是否有动画 30 | loadingTimes: param.loadingTimes || 300,//设置loading动画持续时间,动画持续时间为请求时间加上设置的时间 31 | isHint : param.isHint || false,//是否显示提示框 32 | successHintVal:param.successHintVal || 'Success', //提示框内容 33 | } 34 | return new Promise((resolve, reject) => { 35 | let requestInterceptor = axios.interceptors.request.use((config)=>{//请求拦截器 36 | // 在发送请求之前做些什么 37 | // console.log(config); 38 | ajaxParam.loadingNeed ? Store.loadingStore.ajaxStart() : ''; //开始loading动画 39 | 40 | axios.interceptors.request.eject(requestInterceptor);//清除请求拦截器 41 | return config; 42 | },function (err) { 43 | // 对请求错误做些什么 44 | return reject(err); 45 | }); 46 | let responseInterceptor = axios.interceptors.response.use(function (response) {//响应拦截器 47 | // 对响应数据做点什么 48 | // console.log(response) 49 | 50 | axios.interceptors.response.eject(responseInterceptor);//清除响应拦截器 51 | return response; 52 | }, function (err) { 53 | // 对响应错误做点什么 54 | return reject(err); 55 | }); 56 | 57 | axios.request({ 58 | url: ajaxParam.url, 59 | method: ajaxParam.method, 60 | data: ajaxParam.data, 61 | timeout: ajaxParam.timeout, 62 | responseType:ajaxParam.responseType, 63 | headers: ajaxParam.headers, 64 | cancelToken: new CancelToken(c => { //强行中断请求要用到的 65 | cancel = c; 66 | }), 67 | // transformRequest:[function (data) {//在请求之前对数据进行处理 68 | // console.log(data) 69 | // return data; 70 | // }], 71 | // onUploadProgress: function (progressEvent) {// `onUploadProgress` 允许为上传处理进度事件 72 | // // 对原生进度事件的处理 73 | // }, 74 | // onDownloadProgress: function (progressEvent) {// `onDownloadProgress` 允许为下载处理进度事件 75 | // // 对原生进度事件的处理 76 | // }, 77 | }).then((res) => { 78 | Store.loadingStore.ajaxEnd(ajaxParam.loadingTimes);//停止loading动画 79 | 80 | let data=this.changeData(res.data);//去除FormId 81 | cancel=null;//请求成功将中断axios方法置空 82 | 83 | ajaxParam.isHint ? message.success(ajaxParam.successHintVal) : ''; 84 | 85 | resolve({data:data,res:res}) 86 | }).catch((err) => { 87 | message.error('Error'); 88 | reject(); 89 | 90 | throw new Error(err); 91 | }) 92 | }) 93 | } 94 | 95 | ajax(param){ 96 | this.request(param.data).then(param.success).catch(param.error) 97 | } 98 | 99 | changeData(res){//去除掉返回数据的formID 100 | for(let i in res){ 101 | if(res.hasOwnProperty(i)){ 102 | return res[i]; 103 | } 104 | } 105 | } 106 | 107 | //第一个参数是formId,第二个是数据,但三个是请求还是提交,请求0,提交1 108 | userFormData(formId,data={"0000":{}},method=0){ 109 | if(!formId){throw new Error('没有传递formId!');} 110 | 111 | let obj={}; 112 | obj[formId]={}; 113 | 114 | obj[formId]["method"]=method; 115 | obj[formId]["data"]=data; 116 | 117 | console.log(JSON.stringify(obj)); 118 | return obj; 119 | } 120 | 121 | cancelAjax(str=""){//中断axios请求 122 | if(cancel){ 123 | cancel(str) 124 | } 125 | } 126 | } 127 | 128 | const Axios=new Ajax(); 129 | 130 | export default Axios; -------------------------------------------------------------------------------- /webpack.config.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const HTMLWebpackPlugin = require('html-webpack-plugin'); 4 | const MiniCssExtractPlugin=require('mini-css-extract-plugin'); 5 | const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); 6 | const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); 7 | const HappyPack = require('happypack'); 8 | const AntDesignThemePlugin = require('antd-theme-webpack-plugin');//文档:http://npm.taobao.org/package/antd-theme-webpack-plugin 9 | const NODE_ENV=process.env.NODE_ENV;//区分环境 10 | console.log("--------"+NODE_ENV+"-----------"); 11 | 12 | const options = {//注意, 13 | antDir: path.join(__dirname, './node_modules/antd'), 14 | stylesDir: path.join(__dirname, './src/styles/theme'),//指定皮肤文件夹 15 | varFile: path.join(__dirname, './src/styles/theme/variables.less'),//自己设置默认的主题色 16 | indexFileName: './public/index.html', 17 | mainLessFile: path.join(__dirname, './src/styles/theme/index.less'), 18 | themeVariables: [//要改变的主题变量 19 | '@primary-color', 20 | // '@text-color', 21 | // '@text-color-secondary', 22 | // '@heading-color', 23 | // '@layout-body-background', 24 | // '@btn-primary-bg', 25 | // '@layout-header-background' 26 | ], 27 | generateOnce:false 28 | } 29 | 30 | module.exports={ 31 | entry:['./src/index.js'], 32 | output:{ 33 | filename:'static/js/[name].bundle.js', 34 | path:path.resolve(__dirname,'dist') 35 | }, 36 | resolve:{ 37 | modules:[path.resolve(__dirname, "src"), "node_modules"], 38 | alias:{//别名 39 | '@':path.resolve(__dirname, 'src'), 40 | 'components':path.resolve(__dirname,'./src/components'), 41 | 'pages':path.resolve(__dirname,'src/pages'), 42 | 'static':path.resolve(__dirname,'src/static'), 43 | 'router':path.resolve(__dirname,'src/router'), 44 | 'styles':path.resolve(__dirname,'src/styles'), 45 | 'utils':path.resolve(__dirname,'src/utils'), 46 | 'store':path.resolve(__dirname,'src/store'), 47 | }, 48 | //mainFields:['style','main'],//在node_module下先查找style,再查找main 49 | extensions:['.js','.css','.less'],//import时,不写后缀的时候按顺序查找文件 50 | }, 51 | optimization:{ 52 | minimizer:[ 53 | new UglifyJsPlugin({//压缩js 54 | extractComments: false, // 是否将注释单独提出来一个文件 55 | cache:true, 56 | parallel:true,// 开启并行压缩,充分利用cpu 57 | sourceMap: NODE_ENV === "development", 58 | }), 59 | new OptimizeCSSAssetsPlugin()//压缩css 60 | ], 61 | concatenateModules: true, 62 | splitChunks:{ 63 | cacheGroups:{ 64 | vendors:{//node_modules里的代码 65 | test:/[\\/]node_modules[\\/]/, 66 | chunks: "initial", 67 | name:'vendors', 68 | priority:10, 69 | enforce:true //强制生成 70 | }, 71 | } 72 | } 73 | }, 74 | module:{ 75 | rules:[ 76 | { 77 | test:/\.(js|jsx)$/, 78 | exclude: '/node_modules/', 79 | include:path.resolve(__dirname,'src'), 80 | use:'HappyPack/loader?id=js', 81 | }, 82 | { 83 | test:/\.css$/, 84 | use:'HappyPack/loader?id=css', 85 | }, 86 | { 87 | test:/\.less$/, 88 | use:[ 89 | { 90 | loader:NODE_ENV==="production" ? MiniCssExtractPlugin.loader : "style-loader",//开发环境下使用style-loader(不然不会热更新),生产环境下使用MiniCssExtractPlugin.loader 91 | options:NODE_ENV==="production" ? {publicPath:'../../'} : {} 92 | }, 93 | "css-loader", 94 | { 95 | loader:'postcss-loader', 96 | options:{ 97 | plugins:[ 98 | require('autoprefixer')({ 99 | browsers:['last 2 versions','>5%']//'last 5 versions','>0.01%' 100 | }) 101 | ] 102 | } 103 | }, 104 | { 105 | loader:'less-loader', 106 | options:{ 107 | javascriptEnabled: true, 108 | modifyVars:{ 109 | "@icon-url":'"~antd-iconfont/iconfont"' 110 | } 111 | } 112 | } 113 | ] 114 | }, 115 | { 116 | test:/\.(jpg|jpeg|png|gif|svg)$/, 117 | use:{ 118 | loader:'url-loader', 119 | options:{ 120 | name:'[name].[ext]', 121 | limit:3*1024,//小于3kb使用base64编码 122 | outputPath:'static/img/', 123 | // publicPath:'../img/' 124 | } 125 | } 126 | }, 127 | { 128 | test:/\.(eot|svg|ttf|woff|woff2)$/, 129 | use:[{ 130 | loader:'file-loader', 131 | options:{ 132 | name:'[name].[ext]', 133 | // limit:8192, 134 | outputPath:'static/font/' 135 | } 136 | }] 137 | } 138 | ] 139 | }, 140 | plugins: [ 141 | new HTMLWebpackPlugin({ 142 | template:'./public/index.html',//模板 143 | filename:'index.html',//生成的html文件的名字 144 | minify:{//生产期间使用,直接设置为true,开发时设置为false 145 | // removeAttributeQuotes:true,//删除双引号 146 | removeComments:true,//删除注释 147 | collapseWhitespace:false,//压缩代码 148 | removeStyleLinkTypeAttributes:false, 149 | removeScriptTypeAttributes:false 150 | } 151 | }), 152 | new webpack.DllReferencePlugin({ 153 | manifest: path.resolve(__dirname, 'dist/dll', 'vendor.mainfist.json') 154 | }), 155 | new HappyPack({ 156 | id:'js', 157 | use:[ 158 | { 159 | loader:'babel-loader', 160 | options:{ 161 | presets:[ 162 | [ 163 | '@babel/preset-env', 164 | ], 165 | '@babel/preset-react' 166 | ], 167 | plugins:[ 168 | "@babel/plugin-transform-runtime", 169 | ["@babel/plugin-proposal-decorators", { "legacy": true }],//启用装饰器语法 170 | ["@babel/plugin-proposal-class-properties", { "loose": true }],//使用箭头函数绑定事件 171 | 'babel-plugin-syntax-dynamic-import', 172 | ['import',{ 173 | libraryName:'antd', 174 | libraryDirectory: 'es', 175 | style:true 176 | }] 177 | ], 178 | cacheDirectory: true 179 | } 180 | } 181 | ] 182 | }), 183 | new HappyPack({ 184 | id:'css', 185 | use:[ 186 | { 187 | loader:NODE_ENV==="production" ? MiniCssExtractPlugin.loader : "style-loader",//开发环境下使用style-loader(不然不会热更新),生产环境下使用MiniCssExtractPlugin.loader 188 | options:NODE_ENV==="production" ? {publicPath:'../'} : {} 189 | }, 190 | "css-loader", 191 | { 192 | loader:'postcss-loader', 193 | options:{ 194 | plugins:[ 195 | require('autoprefixer')({ 196 | browsers:['last 5 versions','>0.01%'] 197 | }) 198 | ] 199 | } 200 | } 201 | ] 202 | }), 203 | new AntDesignThemePlugin(options) 204 | ] 205 | } -------------------------------------------------------------------------------- /dist/static/js/main.bundle.js: -------------------------------------------------------------------------------- 1 | !function(u){function e(e){for(var t,n,r=e[0],o=e[1],a=e[2],l=0,i=[];la{display:block;color:rgba(0,0,0,.65)}.ant-menu-item>a:hover{color:#1890ff}.ant-menu-item>a:focus{text-decoration:none}.ant-menu-item>a:before{position:absolute;background-color:transparent;top:0;left:0;bottom:0;right:0;content:""}.ant-menu-item-divider{height:1px;overflow:hidden;background-color:#e8e8e8;line-height:0}.ant-menu-item-active,.ant-menu-item:hover,.ant-menu-submenu-active,.ant-menu-submenu-title:hover,.ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open{color:#1890ff}.ant-menu-horizontal .ant-menu-item,.ant-menu-horizontal .ant-menu-submenu{margin-top:-1px}.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu .ant-menu-submenu-title:hover{background-color:transparent}.ant-menu-item-selected,.ant-menu-item-selected>a,.ant-menu-item-selected>a:hover{color:#1890ff}.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{background-color:#e6f7ff}.ant-menu-inline,.ant-menu-vertical,.ant-menu-vertical-left{border-right:1px solid #e8e8e8}.ant-menu-vertical-right{border-left:1px solid #e8e8e8}.ant-menu-vertical-left.ant-menu-sub,.ant-menu-vertical-right.ant-menu-sub,.ant-menu-vertical.ant-menu-sub{border-right:0;padding:0;-webkit-transform-origin:0 0;transform-origin:0 0}.ant-menu-vertical-left.ant-menu-sub .ant-menu-item,.ant-menu-vertical-right.ant-menu-sub .ant-menu-item,.ant-menu-vertical.ant-menu-sub .ant-menu-item{border-right:0;margin-left:0;left:0}.ant-menu-vertical-left.ant-menu-sub .ant-menu-item:after,.ant-menu-vertical-right.ant-menu-sub .ant-menu-item:after,.ant-menu-vertical.ant-menu-sub .ant-menu-item:after{border-right:0}.ant-menu-vertical-left.ant-menu-sub>.ant-menu-item,.ant-menu-vertical-left.ant-menu-sub>.ant-menu-submenu,.ant-menu-vertical-right.ant-menu-sub>.ant-menu-item,.ant-menu-vertical-right.ant-menu-sub>.ant-menu-submenu,.ant-menu-vertical.ant-menu-sub>.ant-menu-item,.ant-menu-vertical.ant-menu-sub>.ant-menu-submenu{-webkit-transform-origin:0 0;transform-origin:0 0}.ant-menu-horizontal.ant-menu-sub,.ant-menu-vertical-left.ant-menu-sub,.ant-menu-vertical-right.ant-menu-sub,.ant-menu-vertical.ant-menu-sub{min-width:160px}.ant-menu-item,.ant-menu-submenu-title{cursor:pointer;margin:0;padding:0 20px;position:relative;display:block;white-space:nowrap;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),border-color .3s cubic-bezier(.645,.045,.355,1),background .3s cubic-bezier(.645,.045,.355,1),padding .15s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),border-color .3s cubic-bezier(.645,.045,.355,1),background .3s cubic-bezier(.645,.045,.355,1),padding .15s cubic-bezier(.645,.045,.355,1)}.ant-menu-item .anticon,.ant-menu-submenu-title .anticon{min-width:14px;margin-right:10px;-webkit-transition:font-size .15s cubic-bezier(.215,.61,.355,1),margin .3s cubic-bezier(.645,.045,.355,1);transition:font-size .15s cubic-bezier(.215,.61,.355,1),margin .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-item .anticon+span,.ant-menu-submenu-title .anticon+span{-webkit-transition:opacity .3s cubic-bezier(.645,.045,.355,1),width .3s cubic-bezier(.645,.045,.355,1);transition:opacity .3s cubic-bezier(.645,.045,.355,1),width .3s cubic-bezier(.645,.045,.355,1);opacity:1}.ant-menu>.ant-menu-item-divider{height:1px;margin:1px 0;overflow:hidden;padding:0;line-height:0;background-color:#e8e8e8}.ant-menu-submenu-popup{position:absolute;border-radius:4px;z-index:1050}.ant-menu-submenu>.ant-menu{background-color:#fff;border-radius:4px}.ant-menu-submenu>.ant-menu-submenu-title:after{-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow{-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);position:absolute;top:50%;right:16px;width:10px}.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow:before{content:"";position:absolute;vertical-align:baseline;background:#fff;background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.65)),to(rgba(0,0,0,.65)));background-image:linear-gradient(90deg,rgba(0,0,0,.65),rgba(0,0,0,.65));width:6px;height:1.5px;border-radius:2px;-webkit-transition:background .3s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:background .3s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:background .3s cubic-bezier(.645,.045,.355,1),transform .3s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1);transition:background .3s cubic-bezier(.645,.045,.355,1),transform .3s cubic-bezier(.645,.045,.355,1),top .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1)}.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow:before{-webkit-transform:rotate(45deg) translateY(-2px);transform:rotate(45deg) translateY(-2px)}.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical-left>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical-right>.ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical>.ant-menu-submenu-title .ant-menu-submenu-arrow:after{-webkit-transform:rotate(-45deg) translateY(2px);transform:rotate(-45deg) translateY(2px)}.ant-menu-submenu-inline>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:after,.ant-menu-submenu-inline>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical-left>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical-left>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical-right>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical-right>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:before,.ant-menu-submenu-vertical>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:after,.ant-menu-submenu-vertical>.ant-menu-submenu-title:hover .ant-menu-submenu-arrow:before{background:-webkit-gradient(linear,left top,right top,from(#1890ff),to(#1890ff));background:linear-gradient(90deg,#1890ff,#1890ff)}.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:before{-webkit-transform:rotate(-45deg) translateX(2px);transform:rotate(-45deg) translateX(2px)}.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:after{-webkit-transform:rotate(45deg) translateX(-2px);transform:rotate(45deg) translateX(-2px)}.ant-menu-submenu-open.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow{-webkit-transform:translateY(-2px);transform:translateY(-2px)}.ant-menu-submenu-open.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:after{-webkit-transform:rotate(-45deg) translateX(-2px);transform:rotate(-45deg) translateX(-2px)}.ant-menu-submenu-open.ant-menu-submenu-inline>.ant-menu-submenu-title .ant-menu-submenu-arrow:before{-webkit-transform:rotate(45deg) translateX(2px);transform:rotate(45deg) translateX(2px)}.ant-menu-vertical-left .ant-menu-submenu-selected,.ant-menu-vertical-left .ant-menu-submenu-selected>a,.ant-menu-vertical-right .ant-menu-submenu-selected,.ant-menu-vertical-right .ant-menu-submenu-selected>a,.ant-menu-vertical .ant-menu-submenu-selected,.ant-menu-vertical .ant-menu-submenu-selected>a{color:#1890ff}.ant-menu-horizontal{border:0;border-bottom:1px solid #e8e8e8;-webkit-box-shadow:none;box-shadow:none;line-height:46px}.ant-menu-horizontal>.ant-menu-item,.ant-menu-horizontal>.ant-menu-submenu{position:relative;top:1px;float:left;border-bottom:2px solid transparent}.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover{border-bottom:2px solid #1890ff;color:#1890ff}.ant-menu-horizontal>.ant-menu-item>a{display:block;color:rgba(0,0,0,.65)}.ant-menu-horizontal>.ant-menu-item>a:hover{color:#1890ff}.ant-menu-horizontal>.ant-menu-item>a:before{bottom:-2px}.ant-menu-horizontal>.ant-menu-item-selected>a{color:#1890ff}.ant-menu-horizontal:after{content:"\20";display:block;height:0;clear:both}.ant-menu-inline .ant-menu-item,.ant-menu-vertical-left .ant-menu-item,.ant-menu-vertical-right .ant-menu-item,.ant-menu-vertical .ant-menu-item{position:relative}.ant-menu-inline .ant-menu-item:after,.ant-menu-vertical-left .ant-menu-item:after,.ant-menu-vertical-right .ant-menu-item:after,.ant-menu-vertical .ant-menu-item:after{content:"";position:absolute;right:0;top:0;bottom:0;border-right:3px solid #1890ff;-webkit-transform:scaleY(.0001);transform:scaleY(.0001);opacity:0;-webkit-transition:opacity .15s cubic-bezier(.215,.61,.355,1),-webkit-transform .15s cubic-bezier(.215,.61,.355,1);transition:opacity .15s cubic-bezier(.215,.61,.355,1),-webkit-transform .15s cubic-bezier(.215,.61,.355,1);transition:transform .15s cubic-bezier(.215,.61,.355,1),opacity .15s cubic-bezier(.215,.61,.355,1);transition:transform .15s cubic-bezier(.215,.61,.355,1),opacity .15s cubic-bezier(.215,.61,.355,1),-webkit-transform .15s cubic-bezier(.215,.61,.355,1)}.ant-menu-inline .ant-menu-item,.ant-menu-inline .ant-menu-submenu-title,.ant-menu-vertical-left .ant-menu-item,.ant-menu-vertical-left .ant-menu-submenu-title,.ant-menu-vertical-right .ant-menu-item,.ant-menu-vertical-right .ant-menu-submenu-title,.ant-menu-vertical .ant-menu-item,.ant-menu-vertical .ant-menu-submenu-title{padding:0 16px;font-size:14px;line-height:40px;height:40px;margin-top:4px;margin-bottom:4px;overflow:hidden;text-overflow:ellipsis}.ant-menu-inline .ant-menu-submenu,.ant-menu-vertical-left .ant-menu-submenu,.ant-menu-vertical-right .ant-menu-submenu,.ant-menu-vertical .ant-menu-submenu{padding-bottom:.01px}.ant-menu-inline .ant-menu-item:not(:last-child),.ant-menu-vertical-left .ant-menu-item:not(:last-child),.ant-menu-vertical-right .ant-menu-item:not(:last-child),.ant-menu-vertical .ant-menu-item:not(:last-child){margin-bottom:8px}.ant-menu-inline>.ant-menu-item,.ant-menu-inline>.ant-menu-submenu>.ant-menu-submenu-title,.ant-menu-vertical-left>.ant-menu-item,.ant-menu-vertical-left>.ant-menu-submenu>.ant-menu-submenu-title,.ant-menu-vertical-right>.ant-menu-item,.ant-menu-vertical-right>.ant-menu-submenu>.ant-menu-submenu-title,.ant-menu-vertical>.ant-menu-item,.ant-menu-vertical>.ant-menu-submenu>.ant-menu-submenu-title{line-height:40px;height:40px}.ant-menu-inline{width:100%}.ant-menu-inline .ant-menu-item-selected:after,.ant-menu-inline .ant-menu-selected:after{-webkit-transition:opacity .15s cubic-bezier(.645,.045,.355,1),-webkit-transform .15s cubic-bezier(.645,.045,.355,1);transition:opacity .15s cubic-bezier(.645,.045,.355,1),-webkit-transform .15s cubic-bezier(.645,.045,.355,1);transition:transform .15s cubic-bezier(.645,.045,.355,1),opacity .15s cubic-bezier(.645,.045,.355,1);transition:transform .15s cubic-bezier(.645,.045,.355,1),opacity .15s cubic-bezier(.645,.045,.355,1),-webkit-transform .15s cubic-bezier(.645,.045,.355,1);opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1)}.ant-menu-inline .ant-menu-item,.ant-menu-inline .ant-menu-submenu-title{width:calc(100% + 1px)}.ant-menu-inline .ant-menu-submenu-title{padding-right:34px}.ant-menu-inline-collapsed{width:80px}.ant-menu-inline-collapsed>.ant-menu-item,.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item,.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title{left:0;text-overflow:clip;padding:0 32px!important}.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .ant-menu-submenu-arrow,.ant-menu-inline-collapsed>.ant-menu-item .ant-menu-submenu-arrow,.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .ant-menu-submenu-arrow{display:none}.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .anticon,.ant-menu-inline-collapsed>.ant-menu-item .anticon,.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .anticon{font-size:16px;line-height:40px;margin:0}.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item .anticon+span,.ant-menu-inline-collapsed>.ant-menu-item .anticon+span,.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title .anticon+span{max-width:0;display:inline-block;opacity:0}.ant-menu-inline-collapsed-tooltip{pointer-events:none}.ant-menu-inline-collapsed-tooltip .anticon{display:none}.ant-menu-inline-collapsed-tooltip a{color:hsla(0,0%,100%,.85)}.ant-menu-inline-collapsed .ant-menu-item-group-title{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding-left:4px;padding-right:4px}.ant-menu-item-group-list{margin:0;padding:0}.ant-menu-item-group-list .ant-menu-item,.ant-menu-item-group-list .ant-menu-submenu-title{padding:0 16px 0 28px}.ant-menu-root.ant-menu-inline,.ant-menu-root.ant-menu-vertical,.ant-menu-root.ant-menu-vertical-left,.ant-menu-root.ant-menu-vertical-right,.ant-menu-sub.ant-menu-inline{-webkit-box-shadow:none;box-shadow:none}.ant-menu-sub.ant-menu-inline{padding:0;border:0;border-radius:0}.ant-menu-sub.ant-menu-inline>.ant-menu-item,.ant-menu-sub.ant-menu-inline>.ant-menu-submenu>.ant-menu-submenu-title{line-height:40px;height:40px;list-style-type:disc;list-style-position:inside}.ant-menu-sub.ant-menu-inline .ant-menu-item-group-title{padding-left:32px}.ant-menu-item-disabled,.ant-menu-submenu-disabled{color:rgba(0,0,0,.25)!important;cursor:not-allowed;background:none;border-color:transparent!important}.ant-menu-item-disabled>a,.ant-menu-submenu-disabled>a{color:rgba(0,0,0,.25)!important;pointer-events:none}.ant-menu-item-disabled>.ant-menu-submenu-title,.ant-menu-submenu-disabled>.ant-menu-submenu-title{color:rgba(0,0,0,.25)!important;cursor:not-allowed}.ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:rgba(0,0,0,.25)!important}.ant-menu-dark,.ant-menu-dark .ant-menu-sub{color:hsla(0,0%,100%,.65);background:#001529}.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-title .ant-menu-submenu-arrow{opacity:.45;-webkit-transition:all .3s;transition:all .3s}.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-sub .ant-menu-submenu-title .ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-title .ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-title .ant-menu-submenu-arrow:before{background:#fff}.ant-menu-dark.ant-menu-submenu-popup{background:transparent}.ant-menu-dark .ant-menu-inline.ant-menu-sub{background:#000c17;-webkit-box-shadow:0 2px 8px rgba(0,0,0,.45) inset;box-shadow:inset 0 2px 8px rgba(0,0,0,.45)}.ant-menu-dark.ant-menu-horizontal{border-bottom:0}.ant-menu-dark.ant-menu-horizontal>.ant-menu-item,.ant-menu-dark.ant-menu-horizontal>.ant-menu-submenu{border-color:#001529;border-bottom:0;top:0;margin-top:0}.ant-menu-dark.ant-menu-horizontal>.ant-menu-item>a:before{bottom:0}.ant-menu-dark .ant-menu-item,.ant-menu-dark .ant-menu-item-group-title,.ant-menu-dark .ant-menu-item>a{color:hsla(0,0%,100%,.65)}.ant-menu-dark.ant-menu-inline,.ant-menu-dark.ant-menu-vertical,.ant-menu-dark.ant-menu-vertical-left,.ant-menu-dark.ant-menu-vertical-right{border-right:0}.ant-menu-dark.ant-menu-inline .ant-menu-item,.ant-menu-dark.ant-menu-vertical-left .ant-menu-item,.ant-menu-dark.ant-menu-vertical-right .ant-menu-item,.ant-menu-dark.ant-menu-vertical .ant-menu-item{border-right:0;margin-left:0;left:0}.ant-menu-dark.ant-menu-inline .ant-menu-item:after,.ant-menu-dark.ant-menu-vertical-left .ant-menu-item:after,.ant-menu-dark.ant-menu-vertical-right .ant-menu-item:after,.ant-menu-dark.ant-menu-vertical .ant-menu-item:after{border-right:0}.ant-menu-dark.ant-menu-inline .ant-menu-item,.ant-menu-dark.ant-menu-inline .ant-menu-submenu-title{width:100%}.ant-menu-dark .ant-menu-item-active,.ant-menu-dark .ant-menu-item:hover,.ant-menu-dark .ant-menu-submenu-active,.ant-menu-dark .ant-menu-submenu-open,.ant-menu-dark .ant-menu-submenu-selected,.ant-menu-dark .ant-menu-submenu-title:hover{background-color:transparent;color:#fff}.ant-menu-dark .ant-menu-item-active>a,.ant-menu-dark .ant-menu-item:hover>a,.ant-menu-dark .ant-menu-submenu-active>a,.ant-menu-dark .ant-menu-submenu-open>a,.ant-menu-dark .ant-menu-submenu-selected>a,.ant-menu-dark .ant-menu-submenu-title:hover>a{color:#fff}.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow{opacity:1}.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-active>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-open>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-selected>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title:hover>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-title:hover>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:#fff}.ant-menu-dark .ant-menu-item-selected{border-right:0;color:#fff}.ant-menu-dark .ant-menu-item-selected:after{border-right:0}.ant-menu-dark .ant-menu-item-selected>a,.ant-menu-dark .ant-menu-item-selected>a:hover{color:#fff}.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,.ant-menu.ant-menu-dark .ant-menu-item-selected{background-color:#1890ff}.ant-menu-dark .ant-menu-item-disabled,.ant-menu-dark .ant-menu-item-disabled>a,.ant-menu-dark .ant-menu-submenu-disabled,.ant-menu-dark .ant-menu-submenu-disabled>a{opacity:.8;color:hsla(0,0%,100%,.35)!important}.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title{color:hsla(0,0%,100%,.35)!important}.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-item-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:after,.ant-menu-dark .ant-menu-submenu-disabled>.ant-menu-submenu-title>.ant-menu-submenu-arrow:before{background:hsla(0,0%,100%,.35)!important}.ant-tooltip{font-family:Chinese Quote,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-size:14px;font-variant:tabular-nums;line-height:1.5;color:rgba(0,0,0,.65);-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0;list-style:none;position:absolute;z-index:1060;display:block;visibility:visible;max-width:250px}.ant-tooltip-hidden{display:none}.ant-tooltip-placement-top,.ant-tooltip-placement-topLeft,.ant-tooltip-placement-topRight{padding-bottom:8px}.ant-tooltip-placement-right,.ant-tooltip-placement-rightBottom,.ant-tooltip-placement-rightTop{padding-left:8px}.ant-tooltip-placement-bottom,.ant-tooltip-placement-bottomLeft,.ant-tooltip-placement-bottomRight{padding-top:8px}.ant-tooltip-placement-left,.ant-tooltip-placement-leftBottom,.ant-tooltip-placement-leftTop{padding-right:8px}.ant-tooltip-inner{padding:6px 8px;color:#fff;text-align:left;text-decoration:none;background-color:rgba(0,0,0,.75);border-radius:4px;-webkit-box-shadow:0 2px 8px rgba(0,0,0,.15);box-shadow:0 2px 8px rgba(0,0,0,.15);min-height:32px;word-break:break-all}.ant-tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.ant-tooltip-placement-top .ant-tooltip-arrow,.ant-tooltip-placement-topLeft .ant-tooltip-arrow,.ant-tooltip-placement-topRight .ant-tooltip-arrow{bottom:3px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,.75)}.ant-tooltip-placement-top .ant-tooltip-arrow{left:50%;margin-left:-5px}.ant-tooltip-placement-topLeft .ant-tooltip-arrow{left:16px}.ant-tooltip-placement-topRight .ant-tooltip-arrow{right:16px}.ant-tooltip-placement-right .ant-tooltip-arrow,.ant-tooltip-placement-rightBottom .ant-tooltip-arrow,.ant-tooltip-placement-rightTop .ant-tooltip-arrow{left:3px;border-width:5px 5px 5px 0;border-right-color:rgba(0,0,0,.75)}.ant-tooltip-placement-right .ant-tooltip-arrow{top:50%;margin-top:-5px}.ant-tooltip-placement-rightTop .ant-tooltip-arrow{top:8px}.ant-tooltip-placement-rightBottom .ant-tooltip-arrow{bottom:8px}.ant-tooltip-placement-left .ant-tooltip-arrow,.ant-tooltip-placement-leftBottom .ant-tooltip-arrow,.ant-tooltip-placement-leftTop .ant-tooltip-arrow{right:3px;border-width:5px 0 5px 5px;border-left-color:rgba(0,0,0,.75)}.ant-tooltip-placement-left .ant-tooltip-arrow{top:50%;margin-top:-5px}.ant-tooltip-placement-leftTop .ant-tooltip-arrow{top:8px}.ant-tooltip-placement-leftBottom .ant-tooltip-arrow{bottom:8px}.ant-tooltip-placement-bottom .ant-tooltip-arrow,.ant-tooltip-placement-bottomLeft .ant-tooltip-arrow,.ant-tooltip-placement-bottomRight .ant-tooltip-arrow{top:3px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,.75)}.ant-tooltip-placement-bottom .ant-tooltip-arrow{left:50%;margin-left:-5px}.ant-tooltip-placement-bottomLeft .ant-tooltip-arrow{left:16px}.ant-tooltip-placement-bottomRight .ant-tooltip-arrow{right:16px} --------------------------------------------------------------------------------