diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue
index f93cdc0..224e2ff 100644
--- a/src/layout/components/Sidebar/index.vue
+++ b/src/layout/components/Sidebar/index.vue
@@ -17,7 +17,7 @@
:collapse-transition="false"
mode="vertical"
>
-
+
@@ -38,11 +38,12 @@ export default {
},
computed: {
...mapGetters([
+ 'permission_routes',
'sidebar'
]),
- routes() {
- return this.$router.options.routes
- },
+ // routes() {
+ // return this.$router.options.routes
+ // },
activeMenu() {
const route = this.$route
const { meta, path } = route
diff --git a/src/permission.js b/src/permission.js
index 5240522..6725915 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -1,6 +1,6 @@
-import router from './router'
+import router, { asyncRoutes } from './router'
import store from './store'
-import { Message } from 'element-ui'
+// import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import getPageTitle from '@/utils/get-page-title'
@@ -25,23 +25,30 @@ router.beforeEach(async(to, from, next) => {
next({ path: '/' })
NProgress.done()
} else {
- const hasGetUserInfo = store.getters.name
- if (hasGetUserInfo) {
+ if (to.name) {
next()
} else {
- try {
- // get user info
- // await store.dispatch('user/getInfo')
-
- next()
- } catch (error) {
- // remove token and go to login page to re-login
- // await store.dispatch('user/resetToken')
- Message.error(error || 'Has Error')
- next(`/login?redirect=${to.path}`)
- NProgress.done()
- }
+ store.commit('permission/SET_ROUTES', asyncRoutes)
+ router.addRoutes(asyncRoutes)
+ next({ ...to, replace: true })
}
+ // const hasGetUserInfo = store.getters.name
+ // if (hasGetUserInfo) {
+ // next()
+ // } else {
+ // try {
+ // // get user info
+ // // await store.dispatch('user/getInfo')
+ //
+ // next()
+ // } catch (error) {
+ // // remove token and go to login page to re-login
+ // // await store.dispatch('user/resetToken')
+ // Message.error(error || 'Has Error')
+ // next(`/login?redirect=${to.path}`)
+ // NProgress.done()
+ // }
+ // }
}
} else {
/* has no token*/
diff --git a/src/router/index.js b/src/router/index.js
index 28045cc..b4db9a9 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -4,7 +4,8 @@ import Router from 'vue-router'
Vue.use(Router)
/* Layout */
-import Layout from '@/layout'
+import reagentRouter from './modules/reagent'
+import userRouter from '@/router/modules/user'
/**
* Note: sub-menu only appear when route children.length >= 1
@@ -46,199 +47,16 @@ export const constantRoutes = [
path: '/',
redirect: '/home'
},
-
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
- },
- {
- path: '/reagent',
- component: Layout,
- redirect: '/reagent/mainoverview/index'
- },
- {
- path: '/reagent/mainoverview',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'MainOverview',
- meta: { title: '主预览', icon: '主概览' },
- component: () => import('@/views/reagent/mainoverview/index')
- }
- ]
- },
+ }
+]
- {
- path: '/reagent/report',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Report',
- component: () => import('@/views/reagent/report/index'),
- meta: { title: '报告统计', icon: '报表统计' }
- },
- {
- path: 'storeinfo',
- name: 'StoreInfo',
- component: () => import('@/views/reagent/report/storeinfo/index'),
- hidden: true,
- meta: { title: '库存信息总览', icon: '报表统计' }
- },
- {
- path: 'reagentinfo',
- name: 'ReagentInfo',
- component: () => import('@/views/reagent/report/reagentinfo/index'),
- hidden: true,
- meta: { title: '试剂信息详情', icon: '报表统计' }
- },
- {
- path: 'warehousinginfo',
- name: 'WarehousingInfo',
- component: () => import('@/views/reagent/report/warehousinginfo/index'),
- hidden: true,
- meta: { title: '入库信息查询', icon: '报表统计' }
- },
- {
- path: 'inventoryconsuminfo',
- name: 'InventoryConsumInfo',
- component: () => import('@/views/reagent/report/inventoryconsum/index'),
- hidden: true,
- meta: { title: '库存消耗', icon: '报表统计' }
- },
- {
- path: 'reagentconsuminfo',
- name: 'ReagentConsumInfo',
- component: () => import('@/views/reagent/report/reagentconsum/index'),
- hidden: true,
- meta: { title: '试剂消耗', icon: '报表统计' }
- },
- {
- path: 'userconsuminfo',
- name: 'UserConsumInfo',
- component: () => import('@/views/reagent/report/userconsum/index'),
- hidden: true,
- meta: { title: '人员用量消耗', icon: '报表统计' }
- },
- {
- path: 'usefrequencyinfo',
- name: 'UseFrequencyInfo',
- component: () => import('@/views/reagent/report/usefrequency/index'),
- hidden: true,
- meta: { title: '使用频率', icon: '报表统计' }
- },
- {
- path: 'recordinfo/:t',
- name: 'RecordInfo',
- component: () => import('@/views/reagent/report/record/index'),
- hidden: true,
- meta: { title: '记录', icon: '报表统计' }
- }
- ]
- },
- {
- path: '/reagent/warehousing',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Warehousing',
- component: () => import('@/views/reagent/warehousing/index'),
- meta: { title: '试剂入库', icon: '试剂入库' }
- }
- ]
- },
- {
- path: '/reagent/receiving',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Receiving',
- component: () => import('@/views/reagent/receivingandreturn/index'),
- meta: { title: '试剂领用', icon: '试剂领用' }
- }
- ]
- },
- {
- path: '/reagent/sendback',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'SendBack',
- component: () => import('@/views/reagent/receivingandreturn/index'),
- meta: { title: '试剂归还', icon: '试剂归还' }
- }
- ]
- },
- {
- path: '/reagent/weighing',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'weighing',
- component: () => import('@/views/reagent/weighing/index'),
- meta: { title: '试剂称重', icon: '试剂称重' }
- }
- ]
- },
- {
- path: '/reagent/inventory',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Inventory',
- component: () => import('@/views/reagent/inventory/index'),
- meta: { title: '试剂盘点', icon: '库存盘点' }
- }
- ]
- },
- {
- path: '/reagent/database',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Database',
- component: () => import('@/views/reagent/database/index'),
- meta: { title: '化学品数据库', icon: '化学品数据库' }
- }
- ]
- },
- {
- path: '/reagent/management',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Management',
- component: () => import('@/views/reagent/management/index'),
- meta: { title: '试剂管理', icon: '试剂管理' }
- }
- ]
- },
- {
- path: '/reagent/buy',
- component: Layout,
- children: [
- {
- path: 'index',
- name: 'Buy',
- component: () => import('@/views/reagent/buy/index'),
- meta: { title: '请购', icon: '请购' }
- }
- ]
- },
- {
- path: '/gotohome',
- redirect: '/home',
- meta: { title: '返回主页', icon: 'el-icon-arrow-left' }
- },
+export const asyncRoutes = [
+ ...reagentRouter,
+ ...userRouter,
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
diff --git a/src/router/modules/reagent.js b/src/router/modules/reagent.js
new file mode 100644
index 0000000..3b43d6b
--- /dev/null
+++ b/src/router/modules/reagent.js
@@ -0,0 +1,202 @@
+import Layout from '@/layout'
+
+const reagentRouter = [
+ {
+ path: '/reagent',
+ hidden: true,
+ redirect: '/reagent/mainoverview/index'
+ },
+ {
+ path: '/reagent/mainoverview',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'MainOverview',
+ meta: { title: '主预览', icon: '主概览', class: 'reagent' },
+ component: () => import('@/views/reagent/mainoverview/index')
+ }
+ ]
+ },
+ {
+ path: '/reagent/report',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'Report',
+ component: () => import('@/views/reagent/report/index'),
+ meta: { title: '报告统计', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'storeinfo',
+ name: 'StoreInfo',
+ component: () => import('@/views/reagent/report/storeinfo/index'),
+ hidden: true,
+ meta: { title: '库存信息总览', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'reagentinfo',
+ name: 'ReagentInfo',
+ component: () => import('@/views/reagent/report/reagentinfo/index'),
+ hidden: true,
+ meta: { title: '试剂信息详情', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'warehousinginfo',
+ name: 'WarehousingInfo',
+ component: () => import('@/views/reagent/report/warehousinginfo/index'),
+ hidden: true,
+ meta: { title: '入库信息查询', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'inventoryconsuminfo',
+ name: 'InventoryConsumInfo',
+ component: () => import('@/views/reagent/report/inventoryconsum/index'),
+ hidden: true,
+ meta: { title: '库存消耗', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'reagentconsuminfo',
+ name: 'ReagentConsumInfo',
+ component: () => import('@/views/reagent/report/reagentconsum/index'),
+ hidden: true,
+ meta: { title: '试剂消耗', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'userconsuminfo',
+ name: 'UserConsumInfo',
+ component: () => import('@/views/reagent/report/userconsum/index'),
+ hidden: true,
+ meta: { title: '人员用量消耗', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'usefrequencyinfo',
+ name: 'UseFrequencyInfo',
+ component: () => import('@/views/reagent/report/usefrequency/index'),
+ hidden: true,
+ meta: { title: '使用频率', icon: '报表统计', class: 'reagent' }
+ },
+ {
+ path: 'recordinfo/:t',
+ name: 'RecordInfo',
+ component: () => import('@/views/reagent/report/record/index'),
+ hidden: true,
+ meta: { title: '记录', icon: '报表统计', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/warehousing',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'Warehousing',
+ component: () => import('@/views/reagent/warehousing/index'),
+ meta: { title: '试剂入库', icon: '试剂入库', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/receiving',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'Receiving',
+ component: () => import('@/views/reagent/receivingandreturn/index'),
+ meta: { title: '试剂领用', icon: '试剂领用', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/sendback',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'SendBack',
+ component: () => import('@/views/reagent/receivingandreturn/index'),
+ meta: { title: '试剂归还', icon: '试剂归还', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/weighing',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'weighing',
+ component: () => import('@/views/reagent/weighing/index'),
+ meta: { title: '试剂称重', icon: '试剂称重', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/inventory',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'Inventory',
+ component: () => import('@/views/reagent/inventory/index'),
+ meta: { title: '试剂盘点', icon: '库存盘点', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/database',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'Database',
+ component: () => import('@/views/reagent/database/index'),
+ meta: { title: '化学品数据库', icon: '化学品数据库', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/management',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'Management',
+ component: () => import('@/views/reagent/management/index'),
+ meta: { title: '试剂管理', icon: '试剂管理', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/reagent/buy',
+ component: Layout,
+ meta: { class: 'reagent' },
+ children: [
+ {
+ path: 'index',
+ name: 'Buy',
+ component: () => import('@/views/reagent/buy/index'),
+ meta: { title: '请购', icon: '请购', class: 'reagent' }
+ }
+ ]
+ },
+ {
+ path: '/gotohome',
+ redirect: '/home',
+ meta: { title: '返回主页', icon: 'el-icon-arrow-left', class: 'reagent' }
+ }
+]
+
+export default reagentRouter
diff --git a/src/router/modules/user.js b/src/router/modules/user.js
new file mode 100644
index 0000000..0dddf3e
--- /dev/null
+++ b/src/router/modules/user.js
@@ -0,0 +1,40 @@
+// import Layout from '@/layout'
+
+import Layout from '@/layout'
+
+const userRouter = [
+ {
+ path: '/user',
+ redirect: '/user/info/index',
+ hidden: true,
+ meta: { class: 'user' }
+ },
+ {
+ path: '/user/info',
+ component: Layout,
+ meta: { class: 'user' },
+ children: [
+ {
+ path: 'index',
+ component: () => import('@/views/user/index'),
+ name: 'UserInfo',
+ meta: { title: '用户信息', icon: 'lock', class: 'user' }
+ }
+ ]
+ },
+ {
+ path: '/user/role',
+ component: Layout,
+ meta: { class: 'user' },
+ children: [
+ {
+ path: 'index',
+ component: () => import('@/views/user/role/index'),
+ name: 'Role',
+ meta: { title: '角色信息', icon: 'lock', class: 'user' }
+ }
+ ]
+ }
+]
+
+export default userRouter
diff --git a/src/store/getters.js b/src/store/getters.js
index 5ab7b4c..d75c2ad 100644
--- a/src/store/getters.js
+++ b/src/store/getters.js
@@ -3,6 +3,7 @@ const getters = {
device: state => state.app.device,
token: state => state.user.token,
avatar: state => state.user.avatar,
- name: state => state.user.name
+ name: state => state.user.name,
+ permission_routes: state => state.permission.routes
}
export default getters
diff --git a/src/store/index.js b/src/store/index.js
index 03db22e..b79ee33 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -4,6 +4,7 @@ import getters from './getters'
import app from './modules/app'
import settings from './modules/settings'
import user from './modules/user'
+import permission from './modules/permission'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
@@ -11,7 +12,8 @@ const store = new Vuex.Store({
modules: {
app,
settings,
- user
+ user,
+ permission
},
getters,
plugins: [createPersistedState()]
diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js
new file mode 100644
index 0000000..aeb5ee5
--- /dev/null
+++ b/src/store/modules/permission.js
@@ -0,0 +1,69 @@
+import { asyncRoutes, constantRoutes } from '@/router'
+
+/**
+ * Use meta.role to determine if the current user has permission
+ * @param roles
+ * @param route
+ */
+function hasPermission(roles, route) {
+ if (route.meta && route.meta.roles) {
+ return roles.some(role => route.meta.roles.includes(role))
+ } else {
+ return true
+ }
+}
+
+/**
+ * Filter asynchronous routing tables by recursion
+ * @param routes asyncRoutes
+ * @param roles
+ */
+export function filterAsyncRoutes(routes, roles) {
+ const res = []
+
+ routes.forEach(route => {
+ const tmp = { ...route }
+ if (hasPermission(roles, tmp)) {
+ if (tmp.children) {
+ tmp.children = filterAsyncRoutes(tmp.children, roles)
+ }
+ res.push(tmp)
+ }
+ })
+
+ return res
+}
+
+const state = {
+ routes: [],
+ addRoutes: []
+}
+
+const mutations = {
+ SET_ROUTES: (state, routes) => {
+ state.addRoutes = routes
+ state.routes = constantRoutes.concat(routes)
+ }
+}
+
+const actions = {
+ generateRoutes({ commit }, roles) {
+ return new Promise(resolve => {
+ let accessedRoutes
+ if (roles.includes('admin')) {
+ accessedRoutes = asyncRoutes || []
+ } else {
+ accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
+ }
+ commit('SET_ROUTES', accessedRoutes)
+ resolve(accessedRoutes)
+ })
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
diff --git a/src/utils/request.js b/src/utils/request.js
index 2b3f515..a1c994c 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -18,7 +18,7 @@ service.interceptors.request.use(
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
- config.headers['Authorization'] = store.getters.token
+ config.headers['Authorization'] = 'Bearer ' + store.getters.token
}
return config
},
@@ -53,11 +53,20 @@ service.interceptors.response.use(
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
- if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+ if (res.status === 401) {
// to re-login
- MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
- confirmButtonText: 'Re-Login',
- cancelButtonText: 'Cancel',
+ // MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
+ // confirmButtonText: 'Re-Login',
+ // cancelButtonText: 'Cancel',
+ // type: 'warning'
+ // }).then(() => {
+ // store.dispatch('user/resetToken').then(() => {
+ // location.reload()
+ // })
+ // })
+ MessageBox.confirm('登录超时请重新登录', '返回登录', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
index 371de06..5a037b4 100644
--- a/src/views/login/index.vue
+++ b/src/views/login/index.vue
@@ -72,6 +72,7 @@
// import { validUsername } from '@/utils/validate'
import stringify from '@/utils/stringify'
import { login } from '@/api/user/user'
+import { asyncRoutes } from '@/router'
export default {
name: 'Login',
data() {
@@ -131,8 +132,9 @@ export default {
this.loading = true
login(stringify(this.loginForm)).then(res => {
this.$store.commit('user/SET_TOKEN', res.data.token)
- console.log(this.$store.getters.token)
- this.$router.push('/home')
+ this.$store.commit('permission/SET_ROUTES', asyncRoutes)
+ this.$router.addRoutes(asyncRoutes)
+ this.$router.replace('/home')
}).finally(
() => {
this.loading = false
diff --git a/src/views/user/index.vue b/src/views/user/index.vue
new file mode 100644
index 0000000..d954d8a
--- /dev/null
+++ b/src/views/user/index.vue
@@ -0,0 +1,13 @@
+
+ 用户根目录
+
+
+
+
+
diff --git a/src/views/user/role/index.vue b/src/views/user/role/index.vue
new file mode 100644
index 0000000..709727b
--- /dev/null
+++ b/src/views/user/role/index.vue
@@ -0,0 +1,13 @@
+
+ 角色信息
+
+
+
+
+