wangtao il y a 2 ans
Parent
commit
b0e3d467ec

+ 1 - 1
.env.development

@@ -1,7 +1,7 @@
 ENV = 'development'
 
 # 接口地址
-VUE_APP_BASE_API  = 'http://localhost:8000'
+VUE_APP_BASE_API  = 'http://172.16.120.49/hyxtapi/'
 VUE_APP_WS_API = 'ws://localhost:8000'
 #VUE_APP_BASE_API  = 'http://localhost:1538'
 #VUE_APP_WS_API = 'ws://localhost:1538'

+ 1 - 1
.env.production

@@ -2,6 +2,6 @@ ENV = 'production'
 
 # 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇,Nginx 配置
 # 接口地址,注意协议,如果你没有配置 ssl,需要将 https 改为 http
-VUE_APP_BASE_API  = 'http://10.21.39.5:8082'
+VUE_APP_BASE_API  = 'http://172.16.120.49/hyxtapi/'
 # 如果接口是 http 形式, wss 需要改为 ws
 VUE_APP_WS_API = 'ws://10.21.39.5:8082'

BIN
public/favicon.ico


BIN
public/favicon.png


+ 206 - 9
public/index.html

@@ -1,15 +1,212 @@
 <!DOCTYPE html>
 <html>
-  <head>
+
+<head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
     <meta name="renderer" content="webkit">
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
-    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <title><%= webpackConfig.name %></title>
-  </head>
-  <body>
-    <div id="app"></div>
-    <!-- built files will be auto injected -->
-  </body>
-</html>
+    <link rel="icon" href="/favicon.png">
+    <title>
+        <%= webpackConfig.name %>
+    </title>
+    <style>
+        html,
+        body,
+        #app {
+            height: 100%;
+            margin: 0px;
+            padding: 0px;
+            /* background-color: #7171C6; */
+        }
+        
+        .chromeframe {
+            margin: 0.2em 0;
+            background: #ccc;
+            color: #000;
+            padding: 0.2em 0;
+        }
+        
+        #loader-wrapper {
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            z-index: 999999;
+        }
+        
+        #loader {
+            display: block;
+            position: relative;
+            left: 50%;
+            top: 50%;
+            width: 150px;
+            height: 150px;
+            margin: -75px 0 0 -75px;
+            border-radius: 50%;
+            border: 3px solid transparent;
+            border-top-color: #FFF;
+            -webkit-animation: spin 2s linear infinite;
+            -ms-animation: spin 2s linear infinite;
+            -moz-animation: spin 2s linear infinite;
+            -o-animation: spin 2s linear infinite;
+            animation: spin 2s linear infinite;
+            z-index: 1001;
+        }
+        
+        #loader:before {
+            content: "";
+            position: absolute;
+            top: 5px;
+            left: 5px;
+            right: 5px;
+            bottom: 5px;
+            border-radius: 50%;
+            border: 3px solid transparent;
+            border-top-color: #FFF;
+            -webkit-animation: spin 3s linear infinite;
+            -moz-animation: spin 3s linear infinite;
+            -o-animation: spin 3s linear infinite;
+            -ms-animation: spin 3s linear infinite;
+            animation: spin 3s linear infinite;
+        }
+        
+        #loader:after {
+            content: "";
+            position: absolute;
+            top: 15px;
+            left: 15px;
+            right: 15px;
+            bottom: 15px;
+            border-radius: 50%;
+            border: 3px solid transparent;
+            border-top-color: #FFF;
+            -moz-animation: spin 1.5s linear infinite;
+            -o-animation: spin 1.5s linear infinite;
+            -ms-animation: spin 1.5s linear infinite;
+            -webkit-animation: spin 1.5s linear infinite;
+            animation: spin 1.5s linear infinite;
+        }
+        
+        @-webkit-keyframes spin {
+            0% {
+                -webkit-transform: rotate(0deg);
+                -ms-transform: rotate(0deg);
+                transform: rotate(0deg);
+            }
+            100% {
+                -webkit-transform: rotate(360deg);
+                -ms-transform: rotate(360deg);
+                transform: rotate(360deg);
+            }
+        }
+        
+        @keyframes spin {
+            0% {
+                -webkit-transform: rotate(0deg);
+                -ms-transform: rotate(0deg);
+                transform: rotate(0deg);
+            }
+            100% {
+                -webkit-transform: rotate(360deg);
+                -ms-transform: rotate(360deg);
+                transform: rotate(360deg);
+            }
+        }
+        
+        #loader-wrapper .loader-section {
+            position: fixed;
+            top: 0;
+            width: 51%;
+            height: 100%;
+            background: #7171C6;
+            z-index: 1000;
+            -webkit-transform: translateX(0);
+            -ms-transform: translateX(0);
+            transform: translateX(0);
+        }
+        
+        #loader-wrapper .loader-section.section-left {
+            left: 0;
+        }
+        
+        #loader-wrapper .loader-section.section-right {
+            right: 0;
+        }
+        
+        .loaded #loader-wrapper .loader-section.section-left {
+            -webkit-transform: translateX(-100%);
+            -ms-transform: translateX(-100%);
+            transform: translateX(-100%);
+            -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+            transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+        }
+        
+        .loaded #loader-wrapper .loader-section.section-right {
+            -webkit-transform: translateX(100%);
+            -ms-transform: translateX(100%);
+            transform: translateX(100%);
+            -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+            transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+        }
+        
+        .loaded #loader {
+            opacity: 0;
+            -webkit-transition: all 0.3s ease-out;
+            transition: all 0.3s ease-out;
+        }
+        
+        .loaded #loader-wrapper {
+            visibility: hidden;
+            -webkit-transform: translateY(-100%);
+            -ms-transform: translateY(-100%);
+            transform: translateY(-100%);
+            -webkit-transition: all 0.3s 1s ease-out;
+            transition: all 0.3s 1s ease-out;
+        }
+        
+        .no-js #loader-wrapper {
+            display: none;
+        }
+        
+        .no-js h1 {
+            color: #222222;
+        }
+        
+        #loader-wrapper .load_title {
+            font-family: 'Open Sans';
+            color: #FFF;
+            font-size: 19px;
+            width: 100%;
+            text-align: center;
+            z-index: 9999999999999;
+            position: absolute;
+            top: 60%;
+            opacity: 1;
+            line-height: 30px;
+        }
+        
+        #loader-wrapper .load_title span {
+            font-weight: normal;
+            font-style: italic;
+            font-size: 13px;
+            color: #FFF;
+            opacity: 0.5;
+        }
+    </style>
+</head>
+
+<body>
+    <div id="app">
+        <div id="loader-wrapper">
+            <div id="loader"></div>
+            <div class="loader-section section-left"></div>
+            <div class="loader-section section-right"></div>
+            <div class="load_title">正在加载系统资源,请耐心等待</div>
+        </div>
+    </div>
+</body>
+
+
+</html>

+ 31 - 31
src/api/login.js

@@ -1,46 +1,46 @@
 import request from '@/utils/request'
 
 export function login(username, password, code, uuid) {
-  return request({
-    url: 'auth/login',
-    method: 'post',
-    data: {
-      username,
-      password,
-      code,
-      uuid
-    }
-  })
+    return request({
+        url: 'auth/login3',
+        method: 'post',
+        data: {
+            username,
+            password,
+            code,
+            uuid
+        }
+    })
 }
 
 export function loginSSO(username, password) {
-  return request({
-    url: 'auth/login2',
-    method: 'post',
-    data: {
-      username,
-      password
-    }
-  })
+    return request({
+        url: 'auth/login2',
+        method: 'post',
+        data: {
+            username,
+            password
+        }
+    })
 }
 
 export function getInfo() {
-  return request({
-    url: 'auth/info',
-    method: 'get'
-  })
+    return request({
+        url: 'auth/info',
+        method: 'get'
+    })
 }
 
 export function getCodeImg() {
-  return request({
-    url: 'auth/code',
-    method: 'get'
-  })
+    return request({
+        url: 'auth/code',
+        method: 'get'
+    })
 }
 
 export function logout() {
-  return request({
-    url: 'auth/logout',
-    method: 'delete'
-  })
-}
+    return request({
+        url: 'auth/logout',
+        method: 'delete'
+    })
+}

+ 1 - 0
src/assets/icons/svg/eye-open.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>

+ 1 - 0
src/assets/icons/svg/eye.svg

@@ -0,0 +1 @@
+<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>

BIN
src/assets/images/bg.png


BIN
src/assets/logo/logo-b.png


BIN
src/assets/logo/logo.png


+ 7 - 2
src/layout/components/Sidebar/Logo.vue

@@ -2,11 +2,11 @@
   <div class="sidebar-logo-container" :class="{'collapse':collapse}">
     <transition name="sidebarLogoFade">
       <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
-        <img v-if="logo" :src="logo" class="sidebar-logo">
+        <img v-if="logo" src="@/assets/logo/logo.png" class="sidebar-logo2">
         <!-- <h1 v-else class="sidebar-title">{{ title }} </h1> -->
       </router-link>
       <router-link v-else key="expand" class="sidebar-logo-link" to="/">
-        <img v-if="logo" :src="logo" class="sidebar-logo">
+        <img v-if="logo" src="@/assets/logo/logo.png" class="sidebar-logo">
         <!-- <h1 class="sidebar-title">{{ title }} </h1> -->
       </router-link>
     </transition>
@@ -62,6 +62,11 @@ export default {
       vertical-align: middle;
       margin-right: 6px;
     }
+     & .sidebar-logo2{
+      width:40px;
+      height:auto;
+      margin:20px auto;
+    }
 
     & .sidebar-title {
       display: inline-block;

+ 79 - 55
src/router/index.js

@@ -2,75 +2,99 @@ import router from './routers'
 import store from '@/store'
 import Config from '@/settings'
 import NProgress from 'nprogress' // progress bar
-import 'nprogress/nprogress.css'// progress bar style
+import 'nprogress/nprogress.css' // progress bar style
 import { getToken } from '@/utils/auth' // getToken from cookie
 import { buildMenus } from '@/api/system/menu'
 import { filterAsyncRouter } from '@/store/modules/permission'
+import { decrypt } from '@/utils/jsencrypt'
+NProgress.configure({ showSpinner: false }) // NProgress Configuration
 
-NProgress.configure({ showSpinner: false })// NProgress Configuration
-
-const whiteList = ['/login', '/sso', '/meeting/queryMeeting']// no redirect whitelist
+const whiteList = ['/login', '/sso', '/meeting/queryMeeting'] // no redirect whitelist
 
 router.beforeEach((to, from, next) => {
-  if (to.meta.title) {
-    document.title = to.meta.title + ' - ' + Config.title
-  }
-  NProgress.start()
-  if (getToken()) {
-    // 已登录且要跳转的页面是登录页
-    if (to.path === '/login') {
-      next({ path: '/' })
-      NProgress.done()
-    } else {
-      if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
-        store.dispatch('GetInfo').then(() => { // 拉取user_info
-          // 动态路由,拉取菜单
-          loadMenus(next, to)
-        }).catch(() => {
-          store.dispatch('LogOut').then(() => {
-            location.reload() // 为了重新实例化vue-router对象 避免bug
-          })
-        })
-      // 登录时未拉取 菜单,在此处拉取
-      } else if (store.getters.loadMenus) {
-        // 修改成false,防止死循环
-        store.dispatch('updateLoadMenus')
-        loadMenus(next, to)
-      } else {
-        next()
-      }
+    if (to.meta.title) {
+        document.title = to.meta.title + ' - ' + Config.title
     }
-  } else {
-    /* has no token*/
-    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
-      next()
-    } else if (to.path === '/sso') {
-      next()
-    } else if (to.path === '/meeting/queryMeeting') {
-      next()
+    NProgress.start()
+    let url = window.location.hash
+    if (url.indexOf("userNameSaaS") > 0 && url.indexOf("passWordSaaS") > 0) {
+        if (store.getters.roles.length === 0) {
+            let params = {
+                username: undefined,
+                password: undefined
+            }
+            let data = url.split("login?userNameSaaS=")[1].split("&passWordSaaS=")
+            console.log(data)
+            params.username = decrypt(decodeURIComponent(data[0]))
+            params.password = decrypt(decodeURIComponent(data[1]))
+            store.dispatch("Login", params).then((res) => {
+                store.dispatch('GetInfo').then(() => {
+                    loadMenus(next, to)
+                })
+            }).catch(() => {
+                next()
+            })
+        } else {
+            next()
+        }
     } else {
-      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
-      NProgress.done()
+        if (getToken()) {
+            // 已登录且要跳转的页面是登录页
+            if (to.path === '/login') {
+                next({ path: '/' })
+                NProgress.done()
+            } else {
+                if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
+                    store.dispatch('GetInfo').then(() => { // 拉取user_info
+                            // 动态路由,拉取菜单
+                            loadMenus(next, to)
+                        }).catch(() => {
+                            store.dispatch('LogOut').then(() => {
+                                location.reload() // 为了重新实例化vue-router对象 避免bug
+                            })
+                        })
+                        // 登录时未拉取 菜单,在此处拉取
+                } else if (store.getters.loadMenus) {
+                    // 修改成false,防止死循环
+                    store.dispatch('updateLoadMenus')
+                    loadMenus(next, to)
+                } else {
+                    next()
+                }
+            }
+        } else {
+            /* has no token*/
+            if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
+                next()
+            } else if (to.path === '/sso') {
+                next()
+            } else if (to.path === '/meeting/queryMeeting') {
+                next()
+            } else {
+                next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
+                NProgress.done()
+            }
+        }
     }
-  }
+
 })
 
 export const loadMenus = (next, to) => {
-  buildMenus().then(res => {
-    const sdata = JSON.parse(JSON.stringify(res))
-    const rdata = JSON.parse(JSON.stringify(res))
-    const sidebarRoutes = filterAsyncRouter(sdata)
-    const rewriteRoutes = filterAsyncRouter(rdata, true)
-    rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
+    buildMenus().then(res => {
+        const sdata = JSON.parse(JSON.stringify(res))
+        const rdata = JSON.parse(JSON.stringify(res))
+        const sidebarRoutes = filterAsyncRouter(sdata)
+        const rewriteRoutes = filterAsyncRouter(rdata, true)
+        rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
 
-    store.dispatch('GenerateRoutes', rewriteRoutes).then(() => { // 存储路由
-      router.addRoutes(rewriteRoutes) // 动态添加可访问路由表
-      next({ ...to, replace: true })
+        store.dispatch('GenerateRoutes', rewriteRoutes).then(() => { // 存储路由
+            router.addRoutes(rewriteRoutes) // 动态添加可访问路由表
+            next({...to, replace: true })
+        })
+        store.dispatch('SetSidebarRouters', sidebarRoutes)
     })
-    store.dispatch('SetSidebarRouters', sidebarRoutes)
-  })
 }
 
 router.afterEach(() => {
-  NProgress.done() // finish progress bar
-})
+    NProgress.done() // finish progress bar
+})

+ 105 - 92
src/store/modules/user.js

@@ -2,108 +2,121 @@ import { login, loginSSO, getInfo, logout } from '@/api/login'
 import { getToken, setToken, removeToken } from '@/utils/auth'
 
 const user = {
-  state: {
-    token: getToken(),
-    user: {},
-    roles: [],
-    // 第一次加载菜单时用到
-    loadMenus: false
-  },
-
-  mutations: {
-    SET_TOKEN: (state, token) => {
-      state.token = token
-    },
-    SET_USER: (state, user) => {
-      state.user = user
-    },
-    SET_ROLES: (state, roles) => {
-      state.roles = roles
+    state: {
+        token: getToken(),
+        user: {},
+        roles: [],
+        // 第一次加载菜单时用到
+        loadMenus: false
     },
-    SET_LOAD_MENUS: (state, loadMenus) => {
-      state.loadMenus = loadMenus
-    }
-  },
 
-  actions: {
-    // 登录
-    Login({ commit }, userInfo) {
-      const rememberMe = userInfo.rememberMe
-      return new Promise((resolve, reject) => {
-        login(userInfo.username, userInfo.password, userInfo.code, userInfo.uuid).then(res => {
-          setToken(res.token, rememberMe)
-          commit('SET_TOKEN', res.token)
-          setUserInfo(res.user, commit)
-          // 第一次加载菜单时用到, 具体见 src 目录下的 permission.js
-          commit('SET_LOAD_MENUS', true)
-          resolve()
-        }).catch(error => {
-          reject(error)
-        })
-      })
-    },
-    // 单点登录
-    LoginSSO({ commit }, userInfo) {
-      console.log(userInfo)
-      return new Promise((resolve, reject) => {
-        loginSSO(userInfo.username, userInfo.password).then(res => {
-          setToken(res.token, true)
-          commit('SET_TOKEN', res.token)
-          setUserInfo(res.user, commit)
-          // 第一次加载菜单时用到, 具体见 src 目录下的 permission.js
-          commit('SET_LOAD_MENUS', true)
-          resolve()
-        }).catch(error => {
-          reject(error)
-        })
-      })
-    },
-    // 获取用户信息
-    GetInfo({ commit }) {
-      return new Promise((resolve, reject) => {
-        getInfo().then(res => {
-          setUserInfo(res, commit)
-          resolve(res)
-        }).catch(error => {
-          reject(error)
-        })
-      })
-    },
-    // 登出
-    LogOut({ commit }) {
-      return new Promise((resolve, reject) => {
-        logout().then(res => {
-          logOut(commit)
-          resolve()
-        }).catch(error => {
-          logOut(commit)
-          reject(error)
-        })
-      })
+    mutations: {
+        SET_TOKEN: (state, token) => {
+            state.token = token
+        },
+        SET_USER: (state, user) => {
+            state.user = user
+        },
+        SET_ROLES: (state, roles) => {
+            state.roles = roles
+        },
+        SET_LOAD_MENUS: (state, loadMenus) => {
+            state.loadMenus = loadMenus
+        }
     },
 
-    updateLoadMenus({ commit }) {
-      return new Promise((resolve, reject) => {
-        commit('SET_LOAD_MENUS', false)
-      })
+    actions: {
+        // 登录
+        Login({ commit }, userInfo) {
+            const rememberMe = userInfo.rememberMe
+            return new Promise((resolve, reject) => {
+                login(userInfo.username, userInfo.password, userInfo.code, userInfo.uuid).then(res => {
+                    setToken(res.token, rememberMe)
+                    commit('SET_TOKEN', res.token)
+                    setUserInfo(res.user, commit)
+                        // 第一次加载菜单时用到, 具体见 src 目录下的 permission.js
+                    commit('SET_LOAD_MENUS', true)
+                    resolve()
+                }).catch(error => {
+                    reject(error)
+                })
+            })
+        },
+        // 单点登录
+        LoginSSO({ commit }, userInfo) {
+            console.log(userInfo)
+            return new Promise((resolve, reject) => {
+                loginSSO(userInfo.username, userInfo.password).then(res => {
+                    setToken(res.token, true)
+                    commit('SET_TOKEN', res.token)
+                    setUserInfo(res.user, commit)
+                        // 第一次加载菜单时用到, 具体见 src 目录下的 permission.js
+                    commit('SET_LOAD_MENUS', true)
+                    resolve()
+                }).catch(error => {
+                    reject(error)
+                })
+            })
+        },
+        // 登录SaaS
+        LoginSaaS({ commit }, userInfo) {
+            return new Promise((resolve, reject) => {
+                loginSaaS({ username: userInfo.username, password: userInfo.password }).then(res => {
+                    console.log(res)
+                    setToken(res.data)
+                    commit('SET_TOKEN', res.data)
+                    resolve()
+                }).catch(error => {
+                    reject(error)
+                })
+            })
+        },
+        // 获取用户信息
+        GetInfo({ commit }) {
+            return new Promise((resolve, reject) => {
+                getInfo().then(res => {
+                    setUserInfo(res, commit)
+                    resolve(res)
+                }).catch(error => {
+                    reject(error)
+                })
+            })
+        },
+        // 登出
+        LogOut({ commit }) {
+            return new Promise((resolve, reject) => {
+                logout().then(res => {
+                    logOut(commit)
+                    resolve()
+                }).catch(error => {
+                    logOut(commit)
+                    reject(error)
+                })
+            })
+        },
+
+        updateLoadMenus({ commit }) {
+            return new Promise((resolve, reject) => {
+                commit('SET_LOAD_MENUS', false)
+            })
+        }
     }
-  }
 }
 
 export const logOut = (commit) => {
-  commit('SET_TOKEN', '')
-  commit('SET_ROLES', [])
-  removeToken()
+    commit('SET_TOKEN', '')
+    commit('SET_ROLES', [])
+    removeToken()
 }
 
 export const setUserInfo = (res, commit) => {
-  // 如果没有任何权限,则赋予一个默认的权限,避免请求死循环
-  if (res.roles.length === 0) {
-    commit('SET_ROLES', ['ROLE_SYSTEM_DEFAULT'])
-  } else {
-    commit('SET_ROLES', res.roles)
-  }
-  commit('SET_USER', res.user)
+    // 如果没有任何权限,则赋予一个默认的权限,避免请求死循环
+    if (res.roles.length === 0) {
+        commit('SET_ROLES', ['ROLE_SYSTEM_DEFAULT'])
+    } else {
+        commit('SET_ROLES', res.roles)
+    }
+    commit('SET_USER', res.user)
 }
 
-export default user
+export default user

+ 37 - 0
src/utils/jsencrypt.js

@@ -0,0 +1,37 @@
+import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
+
+// 密钥对生成 http://web.chacuo.net/netrsakeypair
+
+const publicKey = `MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxPWP0HTBE9vEeM34Qx03U8oVm
+C6xIqWPRuI5t8J0zEDQudAgXKPjy8E0Q3cX800UNBTx2gUfRRNrONqALKDnJ1SE6
+qCUDeXOez8sa95GQ9d4BX7pSjZLrPfnCBTBtb5LGkY5zmlmtpG2AV9eJr+kQqhs/
+r0c4njwaDjVG4kF3ZQIDAQAB`
+
+const privateKey = `MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALE9Y/QdMET28R4z
+fhDHTdTyhWYLrEipY9G4jm3wnTMQNC50CBco+PLwTRDdxfzTRQ0FPHaBR9FE2s42
+oAsoOcnVITqoJQN5c57Pyxr3kZD13gFfulKNkus9+cIFMG1vksaRjnOaWa2kbYBX
+14mv6RCqGz+vRziePBoONUbiQXdlAgMBAAECgYBjSDdAXEVYrFdeiouYjHwdyAhP
+pERKo5BFvzMRhJIaM353cwnBJ3NkapVQ2Fn6iMIKTB+VZk+7eu1yTAkUluDfLowd
+REZS4ipOBY5UuNnjbXmSOoUQw6vRnox0X4x6S1vd4FBHgpVe1VkiE7Nz5U7Clyd5
+yw2P1lHwMyB/guAH4QJBAN3dGkMASj0jm23maHOfehp/zlACB8HpMKuV4z/bEg45
+nC9Hw5NloUHrXdzEXP1+S46MCH2THflxDVYtnZTRLO0CQQDMgp3Jrn7kkKtNceZF
+R08hLbVmfNlatgONgFJ5JnR+GTQ6o2gwM6SLyoBkfAIiEDpr6c6nBXTU09GOYxBk
++h1ZAkB32pXxVBrG5JF20V3j+GcyIZEGz9H5A0xzpUlambIrVRv2vsH8wo5W2hue
+w8Woe629mBCOJgevVU9rGsFiP44RAkEApbTYAQjAjJakFpZJjKzg8vNEXoye2R9N
+9aOaL8v27A2kAjdRPm050IL+UW0hlVQs4i+KYE7NgX03+PVP3WHD0QJBANLo4PRw
+7Y+dLPAzuazsD3/5SYaSh+KSD/+tVbc6CFvLyfFUKp/a4PzzvGaLo/Ky/ffOY5k0
+hmavbHCKcg+r+hg=`
+
+// 加密
+export function encrypt(txt) {
+    const encryptor = new JSEncrypt()
+    encryptor.setPublicKey(publicKey) // 设置公钥
+    return encryptor.encrypt(txt) // 对数据进行加密
+}
+
+// 解密
+export function decrypt(txt) {
+    const encryptor = new JSEncrypt()
+    encryptor.setPrivateKey(privateKey) // 设置私钥
+    return encryptor.decrypt(txt) // 对数据进行解密
+}

+ 265 - 136
src/views/login.vue

@@ -1,209 +1,338 @@
 <template>
-  <div class="login" :style="'background-image:url('+ Background +');'">
-    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form">
-      <h3 class="title">
-        会议 后台管理系统
-      </h3>
-      <el-form-item prop="username">
+  <div class="login" >
+    <div class="bg" v-if="erp"><img src="@/assets/images/bg.png" alt="" style="width:100%;height:100%;"></div>
+    <div class="logo" v-if="erp">
+      <img src="@/assets/logo/logo-b.png" alt="">
+      <span class="logo_txt">会议管理系统</span>
+    </div>
+    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" v-if="erp">
+      <h3 class="title">用户登录 <span>LOGIN</span></h3>
+      <el-form-item prop="username" >
         <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
           <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
         </el-input>
       </el-form-item>
       <el-form-item prop="password">
-        <el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" @keyup.enter.native="handleLogin">
+        <el-input
+          v-model="loginForm.password"
+          :type="passwordtxt"
+          auto-complete="off"
+          placeholder="密码"
+          @keyup.enter.native="handleLogin"
+        >
           <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+          <svg-icon slot="prefix" icon-class="eye"  class="el-input__icon input-icon"  style="position:absolute;right:-340px"  @click="eyeTab" v-show="passwordtxt =='password'" />
+          <svg-icon slot="prefix" icon-class="eye-open"  class="el-input__icon input-icon"  style="position:absolute;right:-340px"  @click="eyeTab" v-show="passwordtxt =='text'" />
         </el-input>
+
       </el-form-item>
-      <el-form-item prop="code">
-        <el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleLogin">
+      <el-form-item prop="code" v-if="captchaOnOff">
+        <el-input
+          v-model="loginForm.code"
+          auto-complete="off"
+          placeholder="验证码"
+          style="width: 63%"
+          @keyup.enter.native="handleLogin"
+        >
           <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
         </el-input>
         <div class="login-code">
-          <img :src="codeUrl" @click="getCode">
+          <img :src="codeUrl" @click="getCode" class="login-code-img"/>
         </div>
       </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;">
-        记住我
-      </el-checkbox>
+      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;"  @change="memory">记住密码</el-checkbox>
       <el-form-item style="width:100%;">
-        <el-button :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin">
+        <el-button
+          :loading="loading"
+          size="medium"
+          type="primary"
+          style="width:100%;"
+          @click.native.prevent="handleLogin"
+        >
           <span v-if="!loading">登 录</span>
           <span v-else>登 录 中...</span>
         </el-button>
+        <!-- <div style="float: right;" v-if="register">
+          <router-link class="link-type" :to="'/register'">立即注册</router-link>
+        </div> -->
       </el-form-item>
     </el-form>
     <!--  底部  -->
-    <div v-if="$store.state.settings.showFooter" id="el-login-footer">
-      <span v-html="$store.state.settings.footerTxt" />
-      <span> ⋅ </span>
-      <a href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">{{ $store.state.settings.caseNumber }}</a>
+    <div class="el-login-footer" v-if="erp">
+      <!-- <span>Copyright © 2018-2021 yongtian.vip All Rights Reserved.</span> -->
+    </div>
+    <div id="loader-wrapper" v-if="ERPloading">
+        <div id="loader"></div>
+        <div class="loader-section section-left"></div>
+        <div class="loader-section section-right"></div>
+        <div class="load_title">正在加载系统资源,请耐心等待</div>
     </div>
   </div>
 </template>
 
 <script>
-import { encrypt } from '@/utils/rsaEncrypt'
-import Config from '@/settings'
-import { getCodeImg } from '@/api/login'
-import Cookies from 'js-cookie'
-// 登录背景图
-import Background from '@/assets/images/login_bg.png'
+import bgImg from "@/assets/images/bg.png";
+import logoImg from "@/assets/logo/logo-b.png";
+import { getCodeImg } from "@/api/login";
+import Cookies from "js-cookie";
+import { decrypt } from '@/utils/jsencrypt'
+
 export default {
-  name: 'Login',
+  name: "Login",
   data() {
     return {
-      Background: Background,
-      codeUrl: '',
-      cookiePass: '',
+      erp:false,
+      ERPloading:true,
+      passwordtxt:"password",
+      bg:bgImg,
+      logo:logoImg,
+      codeUrl: "",
+      cookiePassword: "",
       loginForm: {
-        username: '',
-        password: '',
+        username: "",
+        password: "",
+        // username: "admin",
+        // password: "admin123",
         rememberMe: false,
-        code: '',
-        uuid: ''
+        code: "",
+        uuid: ""
       },
       loginRules: {
-        username: [{ required: true, trigger: 'blur', message: '用户名不能为空' }],
-        password: [{ required: true, trigger: 'blur', message: '密码不能为空' }],
-        code: [{ required: true, trigger: 'change', message: '验证码不能为空' }]
+        username: [
+          { required: true, trigger: "blur", message: "请输入您的账号" }
+        ],
+        password: [
+          { required: true, trigger: "blur", message: "请输入您的密码" }
+        ],
+        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
       },
       loading: false,
+      // 验证码开关
+      captchaOnOff: false,
+      // 注册开关
+      register: false,
       redirect: undefined
-    }
+    };
   },
   watch: {
     $route: {
       handler: function(route) {
-        this.redirect = route.query && route.query.redirect
+        this.redirect = route.query && route.query.redirect;
       },
       immediate: true
     }
   },
   created() {
-    // 获取验证码
-    this.getCode()
-    // 获取用户名密码等Cookie
-    this.getCookie()
-    // token 过期提示
-    this.point()
+    this.getUrl()
   },
   methods: {
+    getUrl(){
+      let url = this.$route.query
+      if(url.username && url.password){
+        let data = {username:url.username,password:url.password}
+        data.password = encrypt(encodeuricomponent(this.loginForm.password));
+        this.handleLoginERP(data)
+      }else if(url.userNameSaaS && url.passWordSaaS){
+        let data = {
+          username:decrypt(decodeURIComponent(url.userNameSaaS)),
+          password:decrypt(decodeURIComponent(url.passWordSaaS))
+        }
+        Cookies.set("username20220320", data.username, { expires: 30 });
+        Cookies.set("password20220320", url.passWordSaaS, { expires: 30 });
+        this.handleLoginSaaS(data)
+      }else{
+        this.getCode();
+        this.getCookie();
+      }
+    },
+    eyeTab(){
+      if(this.passwordtxt == "password"){
+        this.passwordtxt = "text"
+      }else{
+
+        this.passwordtxt = "password"
+      }
+
+    },
     getCode() {
       getCodeImg().then(res => {
-        this.codeUrl = res.img
-        this.loginForm.uuid = res.uuid
-      })
-      console.log(this.codeUrl)
-      console.log(this.loginForm)
+        this.captchaOnOff = true
+          this.codeUrl =  res.img;
+          this.loginForm.uuid = res.uuid;
+          this.erp = true
+          setTimeout(()=>{
+            this.ERPloading = false
+          },)
+      });
     },
     getCookie() {
-      const username = Cookies.get('username')
-      let password = Cookies.get('password')
-      const rememberMe = Cookies.get('rememberMe')
-      // 保存cookie里面的加密后的密码
-      this.cookiePass = password === undefined ? '' : password
-      password = password === undefined ? this.loginForm.password : password
+      const username = Cookies.get("username20220320");
+      const password = Cookies.get("password20220320");
+      const rememberMe = Cookies.get('rememberMe20220320')
       this.loginForm = {
         username: username === undefined ? this.loginForm.username : username,
-        password: password,
-        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
-        code: ''
-      }
+        password: password === undefined ? this.loginForm.password : decrypt(password),
+        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
+      };
     },
     handleLogin() {
       this.$refs.loginForm.validate(valid => {
-        const user = {
-          username: this.loginForm.username,
-          password: this.loginForm.password,
-          rememberMe: this.loginForm.rememberMe,
-          code: this.loginForm.code,
-          uuid: this.loginForm.uuid
-        }
-        if (user.password !== this.cookiePass) {
-          user.password = encrypt(user.password)
-        }
         if (valid) {
-          this.loading = true
-          if (user.rememberMe) {
-            Cookies.set('username', user.username, { expires: Config.passCookieExpires })
-            Cookies.set('password', user.password, { expires: Config.passCookieExpires })
-            Cookies.set('rememberMe', user.rememberMe, { expires: Config.passCookieExpires })
-          } else {
-            Cookies.remove('username')
-            Cookies.remove('password')
-            Cookies.remove('rememberMe')
-          }
-          this.$store.dispatch('Login', user).then(() => {
-            this.loading = false
-            this.$router.push({ path: this.redirect || '/' })
+          this.loading = true;
+          this.$store.dispatch("Login", this.loginForm).then((res) => {
+            this.$router.push({ path: "/dashboard"}).catch(()=>{});
           }).catch(() => {
-            this.loading = false
-            this.getCode()
-          })
-        } else {
-          console.log('error submit!!')
-          return false
+            this.loading = false;
+            if (this.captchaOnOff) {
+              this.getCode();
+            }
+          });
         }
-      })
+      });
     },
-    point() {
-      const point = Cookies.get('point') !== undefined
-      if (point) {
-        this.$notify({
-          title: '提示',
-          message: '当前登录状态已过期,请重新登录!',
-          type: 'warning',
-          duration: 5000
-        })
-        Cookies.remove('point')
+    memory(){
+      if (this.loginForm.rememberMe) {
+        Cookies.set("username20220320", this.loginForm.username, { expires: 30 });
+        Cookies.set("password20220320", encrypt(encodeuricomponent(this.loginForm.password)), { expires: 30 });
+        Cookies.set('rememberMe20220320', this.loginForm.rememberMe, { expires: 30 });
+      } else {
+        Cookies.remove("username20220320");
+        Cookies.remove("password20220320");
+        Cookies.remove('rememberMe20220320');
       }
+    },
+    handleLoginERP(data) {//erp登录
+
+      this.$store.dispatch("LoginERP", data).then((res) => {
+        this.$router.push({ path: "/dashboard"}).catch(()=>{});
+      }).catch((err) => {
+        location.href = '/dashboard';
+      });
+    },
+    handleLoginSaaS(data) {//SaaS登录
+      this.$store.dispatch("Login", data).then((res) => {
+        this.$router.push({ path: "/dashboard"});
+      }).catch((err) => {
+        location.href = '';
+      });
     }
   }
-}
+};
 </script>
 
-<style rel="stylesheet/scss" lang="scss">
-  .login {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    height: 100%;
-    background-size: cover;
+<style  lang="scss" scoped>
+.bg{
+  width:100%;
+  height:100%;
+  overflow: hidden;
+  position: fixed;
+  top:0;
+  left:0;
+  z-index: -1;
+  .bgimg{
+    width:100%;
+    height:100%;
+    position: absolute;
+    top:0;
+    left:0;
+    z-index: -1;
+  }
+}
+.logo{
+  width:100%;
+  position: fixed;
+  top:0;
+  img{
+    width:152px;
+    margin:10px 2rem 0 20px;
+    vertical-align: middle;
   }
-  .title {
-    margin: 0 auto 30px auto;
-    text-align: center;
-    color: #707070;
+  .logo_txt{
+    font-size: 1.5rem;
+    color:#fff;
+    vertical-align: middle;
+    letter-spacing: 4px;
+  }
+}
+.login {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  // background-image: url("../assets/images/login-background.jpg");
+  background-size: cover;
+}
+.title {
+  margin: 0px auto 30px auto;
+  text-align: left;
+  color: #000000;
+  font-size: 20px;
+  span{
+    margin-left:10px;
+    opacity: 0.25;
   }
+}
 
-  .login-form {
-    border-radius: 6px;
-    background: #ffffff;
-    width: 385px;
-    padding: 25px 25px 5px 25px;
-    .el-input {
-      height: 38px;
-      input {
-        height: 38px;
-      }
-    }
-    .input-icon{
-      height: 39px;width: 14px;margin-left: 2px;
+.login-form {
+  border-radius: 6px;
+  background: #ffffff;
+  width: 456px;
+  padding: 63px 35px;
+  .el-input {
+    height: 40px;
+    font-size: 16px !important;
+    input {
+      height: 40px;
     }
   }
-  .login-tip {
-    font-size: 13px;
-    text-align: center;
-    color: #bfbfbf;
+  .input-icon {
+    height: 39px;
+    width: 14px;
+    margin-left: 2px;
   }
-  .login-code {
-    width: 33%;
-    display: inline-block;
-    height: 38px;
-    float: right;
-    img{
-      cursor: pointer;
-      vertical-align:middle
-    }
+}
+.login-tip {
+  font-size: 13px;
+  text-align: center;
+  color: #bfbfbf;
+}
+.login-code {
+  width: 33%;
+  height: 36px;
+  float: right;
+  img {
+    cursor: pointer;
+    vertical-align: middle;
+    width:100%;
+    height: 36px;
+    margin-top:-1px;
   }
+}
+.el-login-footer {
+  height: 40px;
+  line-height: 40px;
+  position: fixed;
+  bottom: 0;
+  width: 100%;
+  text-align: center;
+  color: #fff;
+  font-family: Arial;
+  font-size: 12px;
+  letter-spacing: 1px;
+}
+::v-deep .el-input__inner{
+  height:36px !important;
+  line-height: 36px !important;
+}
+</style>
+<style>
+html,
+body,
+#app {
+    height: 100%;
+    margin: 0px;
+    padding: 0px;
+    background-color: transparent !important;
+
+}
 </style>

+ 118 - 119
vue.config.js

@@ -3,136 +3,135 @@ const path = require('path')
 const defaultSettings = require('./src/settings.js')
 
 function resolve(dir) {
-  return path.join(__dirname, dir)
+    return path.join(__dirname, dir)
 }
 
 const name = defaultSettings.title // 网址标题
-// const port = 8013 // 端口配置
+    // const port = 8013 // 端口配置
 const port = 1532 // 端口配置
 
 // All configuration item explanations can be find in https://cli.vuejs.org/config/
 module.exports = {
-  // hash 模式下可使用
-  // publicPath: process.env.NODE_ENV === 'development' ? '/' : './',
-  publicPath: '/',
-  outputDir: 'dist',
-  assetsDir: 'static',
-  lintOnSave: process.env.NODE_ENV === 'development',
-  productionSourceMap: false,
-  devServer: {
-    port: port,
-    open: true,
-    overlay: {
-      warnings: false,
-      errors: true
-    },
-    proxy: {
-      '/api': {
-        target: process.env.VUE_APP_BASE_API,
-        changeOrigin: true,
-        pathRewrite: {
-          '^/api': 'api'
+    // hash 模式下可使用
+    publicPath: process.env.NODE_ENV === 'production' ? '/vhyxt/' : '/vhyxt/',
+    outputDir: 'vhyxt',
+    assetsDir: 'static',
+    lintOnSave: process.env.NODE_ENV === 'development',
+    productionSourceMap: false,
+    devServer: {
+        port: port,
+        open: true,
+        overlay: {
+            warnings: false,
+            errors: true
+        },
+        proxy: {
+            '/api': {
+                target: process.env.VUE_APP_BASE_API,
+                changeOrigin: true,
+                pathRewrite: {
+                    '^/api': 'api'
+                }
+            },
+            '/auth': {
+                target: process.env.VUE_APP_BASE_API,
+                changeOrigin: true,
+                pathRewrite: {
+                    '^/auth': 'auth'
+                }
+            }
         }
-      },
-      '/auth': {
-        target: process.env.VUE_APP_BASE_API,
-        changeOrigin: true,
-        pathRewrite: {
-          '^/auth': 'auth'
+    },
+    configureWebpack: {
+        // provide the app's title in webpack's name field, so that
+        // it can be accessed in index.html to inject the correct title.
+        name: name,
+        resolve: {
+            alias: {
+                '@': resolve('src'),
+                '@crud': resolve('src/components/Crud')
+            }
         }
-      }
-    }
-  },
-  configureWebpack: {
-    // provide the app's title in webpack's name field, so that
-    // it can be accessed in index.html to inject the correct title.
-    name: name,
-    resolve: {
-      alias: {
-        '@': resolve('src'),
-        '@crud': resolve('src/components/Crud')
-      }
-    }
-  },
-  chainWebpack(config) {
-    config.plugins.delete('preload') // TODO: need test
-    config.plugins.delete('prefetch') // TODO: need test
+    },
+    chainWebpack(config) {
+        config.plugins.delete('preload') // TODO: need test
+        config.plugins.delete('prefetch') // TODO: need test
 
-    // set svg-sprite-loader
-    config.module
-      .rule('svg')
-      .exclude.add(resolve('src/assets/icons'))
-      .end()
-    config.module
-      .rule('icons')
-      .test(/\.svg$/)
-      .include.add(resolve('src/assets/icons'))
-      .end()
-      .use('svg-sprite-loader')
-      .loader('svg-sprite-loader')
-      .options({
-        symbolId: 'icon-[name]'
-      })
-      .end()
+        // set svg-sprite-loader
+        config.module
+            .rule('svg')
+            .exclude.add(resolve('src/assets/icons'))
+            .end()
+        config.module
+            .rule('icons')
+            .test(/\.svg$/)
+            .include.add(resolve('src/assets/icons'))
+            .end()
+            .use('svg-sprite-loader')
+            .loader('svg-sprite-loader')
+            .options({
+                symbolId: 'icon-[name]'
+            })
+            .end()
 
-    // set preserveWhitespace
-    config.module
-      .rule('vue')
-      .use('vue-loader')
-      .loader('vue-loader')
-      .tap(options => {
-        options.compilerOptions.preserveWhitespace = true
-        return options
-      })
-      .end()
+        // set preserveWhitespace
+        config.module
+            .rule('vue')
+            .use('vue-loader')
+            .loader('vue-loader')
+            .tap(options => {
+                options.compilerOptions.preserveWhitespace = true
+                return options
+            })
+            .end()
 
-    config
-      // https://webpack.js.org/configuration/devtool/#development
-      .when(process.env.NODE_ENV === 'development',
-        config => config.devtool('cheap-source-map')
-      )
+        config
+        // https://webpack.js.org/configuration/devtool/#development
+            .when(process.env.NODE_ENV === 'development',
+            config => config.devtool('cheap-source-map')
+        )
 
-    config
-      .when(process.env.NODE_ENV !== 'development',
-        config => {
-          config
-            .plugin('ScriptExtHtmlWebpackPlugin')
-            .after('html')
-            .use('script-ext-html-webpack-plugin', [{
-            // `runtime` must same as runtimeChunk name. default is `runtime`
-              inline: /runtime\..*\.js$/
-            }])
-            .end()
-          config
-            .optimization.splitChunks({
-              chunks: 'all',
-              cacheGroups: {
-                libs: {
-                  name: 'chunk-libs',
-                  test: /[\\/]node_modules[\\/]/,
-                  priority: 10,
-                  chunks: 'initial' // only package third parties that are initially dependent
-                },
-                elementUI: {
-                  name: 'chunk-elementUI', // split elementUI into a single package
-                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
-                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
-                },
-                commons: {
-                  name: 'chunk-commons',
-                  test: resolve('src/components'), // can customize your rules
-                  minChunks: 3, //  minimum common number
-                  priority: 5,
-                  reuseExistingChunk: true
+        config
+            .when(process.env.NODE_ENV !== 'development',
+                config => {
+                    config
+                        .plugin('ScriptExtHtmlWebpackPlugin')
+                        .after('html')
+                        .use('script-ext-html-webpack-plugin', [{
+                            // `runtime` must same as runtimeChunk name. default is `runtime`
+                            inline: /runtime\..*\.js$/
+                        }])
+                        .end()
+                    config
+                        .optimization.splitChunks({
+                            chunks: 'all',
+                            cacheGroups: {
+                                libs: {
+                                    name: 'chunk-libs',
+                                    test: /[\\/]node_modules[\\/]/,
+                                    priority: 10,
+                                    chunks: 'initial' // only package third parties that are initially dependent
+                                },
+                                elementUI: {
+                                    name: 'chunk-elementUI', // split elementUI into a single package
+                                    priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+                                    test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+                                },
+                                commons: {
+                                    name: 'chunk-commons',
+                                    test: resolve('src/components'), // can customize your rules
+                                    minChunks: 3, //  minimum common number
+                                    priority: 5,
+                                    reuseExistingChunk: true
+                                }
+                            }
+                        })
+                    config.optimization.runtimeChunk('single')
                 }
-              }
-            })
-          config.optimization.runtimeChunk('single')
-        }
-      )
-  },
-  transpileDependencies: [
-    'vue-echarts',
-    'resize-detector'
-  ]
-}
+            )
+    },
+    transpileDependencies: [
+        'vue-echarts',
+        'resize-detector'
+    ]
+}