权限控制

This commit is contained in:
Jason 2022-04-20 12:10:22 +08:00
parent f20f1af16b
commit 143da05631
30 changed files with 322 additions and 550 deletions

View File

@ -17,7 +17,7 @@
"nprogress": "^0.2.0",
"vue": "^3.2.25",
"vue-echarts": "^6.0.0",
"vue-router": "^4.0.0-0",
"vue-router": "^4.0.14",
"vuedraggable": "^4.1.0",
"vuex": "^4.0.0-0"
},

View File

@ -1,18 +1,14 @@
<template>
<keep-alive>
<router-view v-if="keepAlive && routerAlive" />
</keep-alive>
<router-view v-if="!keepAlive && routerAlive" />
<router-view v-if="routerAlive" />
</template>
<script lang="ts">
import { computed, defineComponent, ref, nextTick, provide, onMounted } from 'vue'
import { defineComponent, ref, nextTick, provide, onMounted } from 'vue'
import { useAdmin } from './core/hooks/app'
export default defineComponent({
setup() {
const { store, route } = useAdmin()
const routerAlive = ref(true)
const keepAlive = computed(() => route.meta.keepAlive)
const reload = () => {
routerAlive.value = false
nextTick(() => {
@ -36,8 +32,7 @@ export default defineComponent({
document.head.appendChild(favicon)
})
return {
routerAlive,
keepAlive
routerAlive
}
}
})

View File

@ -56,9 +56,9 @@ export function apiConfigGetMenu() {
return request.get('/system/menu/lists')
}
// 角色权限
export function apiConfigGetAuth() {
return request.get('/config/getAuth')
// 菜单路由
export function apiConfigGetRoutes() {
return request.get('/system/menu/menus')
}
/* 菜单 */

View File

@ -3,7 +3,7 @@ import { App } from 'vue'
const modules = import.meta.globEager('./modules/*.ts')
export default (app: App<Element>) => {
Object.keys(modules).forEach(key => {
const name = key.replace(/^\.\/(.*)\.\w+$/, '$1')
const name = key.replace(/^\.\/.*\/(.*)\.\w+$/, '$1')
app.directive(name, modules[key].default)
})
}

View File

@ -0,0 +1,29 @@
/**
* perm ()
*
* <el-button v-perm="['system:admin:edit']"></el-button>
* copyValue为需要复制的值
*/
import store from "@/store"
export default {
mounted: (el: HTMLElement, binding: any) => {
const { value } = binding
const permissions = store.getters && store.getters.permission
const all_permission = "*";
if (Array.isArray(value)) {
if (value.length > 0) {
const hasPermission = permissions.some((key: string) => {
return all_permission == key || value.includes(key)
})
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
}
} else {
throw new Error(`like v-perm="['system:admin:edit']`)
}
}
}

View File

@ -0,0 +1,68 @@
import { RouteRecordRaw, RouterView } from "vue-router"
export enum MenuType{
Catalogue = 'M',
Menu = 'C',
Button = 'A'
}
// 匹配views里面所有的.vue文件动态引入
const modules = import.meta.glob('@/views/**/*.vue')
// 过滤路由所需要的数据
export function filterAsyncRoutes(routes: any[], firstRoute = true) {
return routes.map((route => {
const routeRecord = createRouteRecord(route, firstRoute)
if (route.children != null && route.children && route.children.length) {
routeRecord.children = filterAsyncRoutes(route.children, false)
}
return routeRecord
}))
}
// 创建一条路由记录
export function createRouteRecord(route: any, firstRoute: boolean): RouteRecordRaw {
//@ts-ignore
const routeRecord: RouteRecordRaw = {
path: firstRoute ? `/${route.paths}` : route.paths,
name: route.paths,
meta: {
hidden: !route.isShow,
keepAlive: !!route.isCache,
title: route.menuName,
perms: route.perms,
query: route.params,
icon: route.menuIcon,
activePath: route.selected
},
}
switch (route.menuType) {
case MenuType.Catalogue:
routeRecord.component = RouterView
break
case MenuType.Menu:
routeRecord.component = loadRouteView(route.component)
break
}
return routeRecord
}
console.log(modules)
// 动态加载组件
export function loadRouteView(component: string) {
try {
const key = Object.keys(modules).find((key) => {
return key.includes(`${component}.vue`)
})
if (key) {
return modules[key]
} else {
throw Error(`找不到组件${component},请确保组件路径正确`)
}
} catch (error) {
console.error(error)
return RouterView
}
}

1
admin/src/env.d.ts vendored
View File

@ -17,3 +17,4 @@ declare module 'nprogress' {
export function start(): void
export function done(): void
}

View File

@ -11,18 +11,9 @@
background-color="#2a2c41"
:default-active="currentPath"
text-color="#E5E5E5"
router
>
<template v-for="(item, index) in sidebar" :key="index">
<sub-menu :route="item">
<template v-for="(item, index) in item?.children" :key="index">
<sub-menu :route="item">
<template v-for="(item, index) in item?.children" :key="index">
<sub-menu :route="item"></sub-menu>
</template>
</sub-menu>
</template>
</sub-menu>
<sub-menu :route="item" :path="item.path"/>
</template>
</el-menu>
</el-scrollbar>
@ -41,7 +32,7 @@ export default defineComponent({
setup() {
const { store, route } = useAdmin()
const sidebar = computed(() => store.state.permission.sidebar)
const currentPath = computed(() => route.meta?.parent ?? route.path)
const currentPath = computed(() => route.meta?.activeMenu ?? route.path)
const config = computed(() => store.getters.config)
return {
config,

View File

@ -1,21 +1,38 @@
<template>
<template v-if="!route.meta.hidden">
<el-sub-menu v-if="hasChildren" :index="route.path">
<div v-if="!route.meta.hidden">
<el-sub-menu v-if="hasChildren" :index="path">
<template #title>
<i class="iconfont m-r-10" :class="route.meta.icon"></i>
<span>{{ route.meta.title }}</span>
</template>
<slot></slot>
<template #default>
<sub-menu
v-for="(item, index) in route.children"
:key="index"
:route="item"
:path="resolvePath(item.path)"
/>
</template>
</el-sub-menu>
<el-menu-item v-else :index="route.path">
<i class="iconfont m-r-10" :class="route.meta.icon"></i>
<span>{{ route.meta.title }}</span>
</el-menu-item>
</template>
<router-link
v-else
:to="{
path: path,
query: resolveQuery
}"
>
<el-menu-item :index="path">
<i class="iconfont m-r-10" :class="route.meta.icon"></i>
<span>{{ route.meta.title }}</span>
</el-menu-item>
</router-link>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue'
import { queryToObject } from '@/utils/util'
import { isQuery } from '@/utils/validate'
import { computed, defineComponent, toRefs } from 'vue'
import { RouteRecordRaw } from 'vue-router'
export default defineComponent({
components: {},
@ -23,15 +40,40 @@ export default defineComponent({
route: {
type: Object,
default: () => ({})
},
path: {
type: String
}
},
setup(props) {
const { path, route } = toRefs(props)
//
const hasChildren = computed(() => {
const children: RouteRecordRaw[] = props.route.children ?? []
const children: RouteRecordRaw[] = route.value.children ?? []
return !!children.filter(item => !item.meta?.hidden).length
})
//
const resolvePath = computed(() => (p?: string) => {
return p !== undefined ? `${path.value}/${p}` : path.value
})
// '{id:1}'|| id=1 => {id: 1}
const resolveQuery = computed(() => {
const query = route.value.query
try {
if (isQuery(query)) {
return queryToObject(query)
} else {
return JSON.parse(query)
}
} catch (error) {
}
})
return {
hasChildren
hasChildren,
resolvePath,
resolveQuery
}
}
})

View File

@ -2,18 +2,25 @@
<div class="layout-main">
<el-scrollbar>
<div class="p-15">
<perm />
<router-view />
</div>
</el-scrollbar>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import Perm from './perm.vue'
import { useAdmin } from '@/core/hooks/app'
import { computed, defineComponent } from 'vue'
export default defineComponent({
components: {
Perm
name: 'layout-main',
setup() {
const { route } = useAdmin()
const keepAlive = computed(() => {
return route.meta.keepAlive
})
return {
keepAlive
}
}
})
</script>

View File

@ -4,7 +4,7 @@
import NProgress from 'nprogress'
import store from './store'
import router, { asyncRoutes } from './router'
import router from './router'
import 'nprogress/nprogress.css'
// NProgress配置
@ -22,16 +22,28 @@ router.beforeEach(async (to, from, next) => {
const token = store.getters.token
if (token) {
// 获取用户信息
if (store.getters.permission == null) {
store.commit('permission/setSidebar', asyncRoutes[0].children)
await store.dispatch('user/getUser')
await store.dispatch('permission/getPermission')
}
if (to.path === loginPath) {
next({ path: defaultPath })
if (store.getters.permission.length === 0) {
try {
await store.dispatch('user/getUser')
const routes = await store.dispatch('permission/generateRoutes')
routes.forEach((route: any) => {
router.addRoute('index', route) // 动态添加可访问路由表
})
console.log(router.getRoutes())
if (to.path === '/login') {
next({ path: '/' })
} else {
next({ ...to, replace: true }) //确保addRoutes已完成
}
} catch {
await store.dispatch('user/logout')
next({ path: loginPath, query: { redirect: to.fullPath } })
NProgress.done()
}
} else {
next()
}
} else if (whiteList.includes(to.path as string)) {
// 在免登录白名单,直接进入
next()

View File

@ -1,55 +1,76 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import workbench from '@/views/workbench/index.vue'
import Layout from '@/layout/index.vue'
import Error404 from '@/views/error/404.vue'
import Error500 from '@/views/error/500.vue'
// Router modules
import setting from './modules/setting'
import permission from './modules/permission'
import decoration from './modules/decoration'
import content from './modules/content'
import channel from './modules/channel'
import application from './modules/application'
export const asyncRoutes: Array<RouteRecordRaw> = [
/**
* Note: 路由配置项
*
* name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
*
* meta : {
keepAlive: true // 如果设置为true则不会被 <keep-alive> 缓存(默认 false)
title: 'title' // 设置该路由在侧边栏的名字
icon: 'svg-name' // 设置该路由的图标
activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
query: '{"id": 1}' // 访问路由的默认传递参数
hidden: true // 当设置 true 的时候该路由不会再侧边栏出现
}
*/
// 公共路由
export const constantRoutes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: 'workbench',
name: 'index',
component: Layout
},
{
path: '/permission',
component: Layout,
children: [
{
path: '/workbench',
component: workbench,
meta: { title: '工作台', icon: 'icon-home', permission: ['view'] }
path: 'admin/edit',
component: () => import('@/views/permission/admin/edit.vue'),
meta: { title: '编辑管理员', activeMenu: '/permission/admin' }
},
// decoration, // 装修管理
// application,// 应用管理
// content, // 内容管理
// channel, // 渠道管理
permission,
setting
{
path: 'menu/edit',
component: () => import('@/views/permission/menu/edit.vue'),
meta: { title: '编辑菜单', activeMenu: '/permission/menu' }
},
{
path: 'role/edit',
component: () => import('@/views/permission/role/edit.vue'),
meta: { title: '编辑角色', activeMenu: '/permission/role' }
}
]
}
]
export const constRoutes: Array<RouteRecordRaw> = [
},
{
path: '/login',
component: () => import('@/views/account/login.vue')
},
{
path: '/error/500',
component: Error500
path: '/500',
component: () => import('@/views/error/500.vue')
},
{ path: '/:pathMatch(.*)*', name: '404', component: Error404 }
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue')
}
]
export const getAsyncRoutes = () => {
return asyncRoutes
}
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [...asyncRoutes, ...constRoutes]
routes: constantRoutes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
},
})
export default router

View File

@ -1,40 +0,0 @@
import { RouteRecordRaw, RouterView } from 'vue-router'
const routes: RouteRecordRaw = {
path: '/application',
redirect: '/application/notification',
component: RouterView,
meta: { title: '应用管理', icon: 'icon-setting' },
children: [
{
path: '/application/notification',
redirect: '/application/notification/index',
component: RouterView,
meta: { title: '消息通知' },
children: [
{
path: '/application/notification/index',
component: () => import('@/views/application/notification/index.vue'),
meta: { title: '通知设置', permission: ['view'] },
},
{
path: '/application/notification/detail',
component: () => import('@/views/application/notification/detail.vue'),
meta: { hidden: true, title: '通知设置', permission: ['view'] },
},
{
path: '/application/sms/index',
component: () => import('@/views/application/sms/index.vue'),
meta: { title: '短信设置', permission: ['view'] },
},
{
path: '/application/sms/detail',
component: () => import('@/views/application/sms/detail.vue'),
meta: { hidden: true, title: '短信设置', permission: ['view'] },
},
],
},
],
}
export default routes

View File

@ -1,106 +0,0 @@
import { RouteRecordRaw, RouterView } from "vue-router"
const routes: RouteRecordRaw = {
path: '/channel',
name: 'channel',
meta: { title: '渠道管理', icon: 'icon-setting' },
component: RouterView,
children: [{
path: '/channel/mp_wechat',
name: 'mp_wechat',
meta: {
title: '微信公众号',
parentPath: '/channel',
},
component: RouterView,
children: [{
path: '/channel/mp_wechat/index',
name: 'mp_wechat_index',
meta: {
title: '渠道设置',
parentPath: '/channel',
permission: ['view']
},
component: () => import('@/views/channel/mp_wechat/index.vue'),
}, {
path: '/channel/mp_wechat/menu',
name: 'mp_wechat_menu',
meta: {
title: '菜单管理',
parentPath: '/channel',
permission: ['view']
},
component: () => import('@/views/channel/mp_wechat/menu.vue'),
}, {
path: '/channel/mp_wechat/reply/follow_reply',
name: 'follow_reply',
meta: {
title: '关注回复',
parentPath: '/channel',
permission: ['view']
},
component: () => import('@/views/channel/mp_wechat/reply/follow_reply.vue'),
}, {
path: '/channel/mp_wechat/reply/keyword_reply',
name: 'keyword_reply',
meta: {
title: '关键字回复',
parentPath: '/channel',
permission: ['view']
},
component: () => import('@/views/channel/mp_wechat/reply/keyword_reply.vue'),
}, {
path: '/channel/mp_wechat/reply/default_reply',
name: 'default_reply',
meta: {
title: '默认回复',
parentPath: '/channel',
permission: ['view']
},
component: () => import('@/views/channel/mp_wechat/reply/default_reply.vue'),
}, {
path: '/channel/mp_wechat/reply/reply_edit',
name: 'reply_edit',
meta: {
title: '默认编辑',
parentPath: '/channel',
hidden: true,
permission: ['view']
},
component: () => import('@/views/channel/mp_wechat/reply/reply_edit.vue'),
}]
}, {
path: '/channel/wechat_app',
name: 'wechat_app',
meta: {
title: '微信小程序',
parentPath: '/channel'
},
component: () => import('@/views/channel/wechat_app/index.vue')
}, {
path: '/channel/app_store',
name: 'app_store',
meta: {
title: 'APP',
parentPath: '/channel',
},
component: () => import('@/views/channel/app_store/index.vue'),
}, {
path: '/channel/h5_store',
name: 'h5_store',
meta: {
title: 'H5',
parentPath: '/channel',
},
component: () => import('@/views/channel/h5_store/index.vue')
}, {
path: '/wechat/wechat_platform',
name: 'wechat_platform',
meta: {
title: '微信开放平台',
parentPath: '/channel',
},
component: () => import('@/views/channel/wechat_platform/index.vue')
}]
}
export default routes

View File

@ -1,66 +0,0 @@
import { RouteRecordRaw, RouterView } from 'vue-router'
const routes: RouteRecordRaw = {
path: '/content',
redirect: '/content/advertising',
component: RouterView,
meta: { title: '内容管理', icon: 'icon-setting' },
children: [
// {
// path: '/content/advertising',
// redirect: '/content/advertising/lists',
// component: RouterView,
// meta: { title: '广告管理' },
// children: [
// {
// path: '/content/advertising/lists',
// component: () => import('@/views/content/advertising/advertising.vue'),
// meta: { title: '广告列表' },
// },
// {
// path: '/content/advertising/advertising_edit',
// component: () => import('@/views/decoration/advertising_edit.vue'),
// meta: {
// title: '广告列表',
// parent: '/content/advertising/lists',
// hidden: true,
// },
// },
// {
// path: '/content/advertising/position',
// component: () => import('@/views/content/advertising/position.vue'),
// meta: { title: '广告位' },
// },
// ],
// },
{
path: '/content/information',
redirect: '/content/information/lists',
component: RouterView,
meta: { title: '资讯管理' },
children: [
{
path: '/content/information/lists',
component: () => import('@/views/content/information/lists.vue'),
meta: { title: '资讯列表' },
},
{
path: '/content/information/information_edit',
component: () => import('@/views/content/information/information_edit.vue'),
meta: {
title: '资讯列表',
parent: '/content/information/lists',
hidden: true,
},
},
{
path: '/content/information/position',
component: () => import('@/views/content/information/category.vue'),
meta: { title: '资讯分类' },
},
],
},
],
}
export default routes

View File

@ -1,38 +0,0 @@
import { RouteRecordRaw, RouterView } from 'vue-router'
const routes: RouteRecordRaw = {
path: '/decoration',
redirect: '/decoration/home',
component: RouterView,
meta: { title: '装修管理', icon: 'icon-setting' },
children: [
{
path: '/decoration/home',
component: () => import('@/views/decoration/home.vue'),
meta: { title: '首页装修' },
},
{
path: '/decoration/home_edit',
component: () => import('@/views/decoration/home_edit.vue'),
meta: { title: '首页装修', parent: '/decoration/home', hidden: true },
},
{
path: '/decoration/tabbar',
component: () => import('@/views/decoration/tabbar.vue'),
meta: { title: '底部标签栏' },
},
{
path: '/decoration/advertising',
component: () => import('@/views/decoration/advertising.vue'),
meta: { title: '广告管理' },
},
{
path: '/decoration/advertising_edit',
component: () => import('@/views/decoration/advertising_edit.vue'),
meta: { title: '广告管理', parent: '/decoration/advertising', hidden: true },
},
],
}
export default routes

View File

@ -1,54 +0,0 @@
import { RouteRecordRaw, RouterView } from 'vue-router'
const routes: RouteRecordRaw = {
path: '/permission',
redirect: '/permission/admin',
component: RouterView,
meta: { title: '权限管理', icon: 'icon-quanxian' },
children: [
{
path: '/permission/admin',
component: () => import('@/views/permission/admin/index.vue'),
meta: { title: '管理员', permission: ['view'] }
},
{
path: '/permission/admin/edit',
component: () => import('@/views/permission/admin/edit.vue'),
meta: {
title: '管理员',
parent: '/permission/admin',
hidden: true
}
},
{
path: '/permission/role',
component: () => import('@/views/permission/role/index.vue'),
meta: { title: '角色', permission: ['view'] }
},
{
path: '/permission/role/edit',
component: () => import('@/views/permission/role/edit.vue'),
meta: {
title: '角色',
parent: '/permission/role',
hidden: true
}
},
{
path: '/permission/menu',
component: () => import('@/views/permission/menu/index.vue'),
meta: { title: '菜单', permission: ['view'] }
},
{
path: '/permission/menu/edit',
component: () => import('@/views/permission/menu/edit.vue'),
meta: {
title: '菜单',
parent: '/permission/menu',
hidden: true
}
}
]
}
export default routes

View File

@ -1,132 +0,0 @@
import { RouteRecordRaw, RouterView } from 'vue-router'
const routes: RouteRecordRaw = {
path: '/setting',
redirect: '/setting/service',
component: RouterView,
meta: { title: '系统设置', icon: 'icon-setting' },
children: [
{
path: '/setting/service',
redirect: '/setting/service/online_service',
component: RouterView,
meta: {
title: '客服设置',
hidden: true
},
children: [
{
path: '/setting/service/online_service',
component: () => import('@/views/setting/service/online_service.vue'),
meta: {
title: '在线客服'
}
}
]
},
{
path: '/setting/website',
redirect: '/setting/website/information',
component: RouterView,
meta: { title: '网站设置' },
children: [
{
path: '/setting/website/information',
component: () => import('@/views/setting/website/information.vue'),
meta: {
title: '网站信息',
permission: ['view']
}
},
{
path: '/setting/website/filing',
component: () => import('@/views/setting/website/filing.vue'),
meta: {
title: '备案信息',
permission: ['view']
}
},
{
path: '/setting/website/protocol',
component: () => import('@/views/setting/website/protocol.vue'),
meta: {
title: '政策/协议',
permission: ['view'],
hidden: true
}
}
]
},
{
path: '/setting/user',
redirect: '/setting/user',
component: RouterView,
meta: {
title: '用户设置',
hidden: true
},
children: [
{
path: '/setting/user',
component: () => import('@/views/setting/user/index.vue'),
meta: {
title: '用户设置',
permission: ['view']
}
},
{
path: '/setting/user/login',
component: () => import('@/views/setting/user/login.vue'),
meta: {
title: '登录注册',
permission: ['view']
}
}
]
},
{
path: '/setting/system',
redirect: '/setting/system/environment',
component: RouterView,
meta: { title: '系统维护' },
children: [
{
path: '/setting/website/environment',
component: () => import('@/views/setting/system/environment.vue'),
meta: {
title: '系统环境',
permission: ['view']
}
},
{
path: '/setting/website/journal',
component: () => import('@/views/setting/system/journal.vue'),
meta: {
title: '系统日志',
permission: ['view']
}
},
{
path: '/setting/website/cache',
component: () => import('@/views/setting/system/cache.vue'),
meta: {
title: '系统缓存',
permission: ['view']
}
}
]
},
{
// component: RouterView,
path: '/setting/personal/personal_data',
component: () => import('@/views/setting/personal/personal_data.vue'),
meta: {
title: '个人设置',
permission: ['view'],
hidden: true
}
}
]
}
export default routes

View File

@ -9,8 +9,7 @@ const getters: GetterTree<rootState, any> = {
// 通用配置
config: state => state.app.config,
// 权限列表
permission: state => state.permission.permission,
isAdmin: state => state.permission.isAdmin
permission: state => state.user.permissions
}
export default getters

View File

@ -7,7 +7,8 @@ export interface AppModule {
const app: Module<AppModule, any> = {
namespaced: true,
state: {
config: {}
// 公共配置
config: {},
},
mutations: {
setConfig(state, data) {

View File

@ -1,45 +1,40 @@
import { Module } from 'vuex'
import { RouteRecordRaw } from 'vue-router'
import { apiConfigGetAuth } from '@/api/auth'
import { apiConfigGetRoutes } from '@/api/auth'
import { filterAsyncRoutes } from '@/core/lib/router'
export interface PermissionModule {
routes: Array<RouteRecordRaw>
sidebar: Array<RouteRecordRaw>
permission: any[] | null
isAdmin: number
}
const permission: Module<PermissionModule, any> = {
namespaced: true,
state: {
// 路由
routes: [],
// 左侧菜单
sidebar: [],
// 权限列表
permission: null,
// 是否是管理员
isAdmin: 0
sidebar: []
},
getters: {},
mutations: {
setSidebar(state, data) {
state.sidebar = data
},
setPermission(state, data) {
state.permission = data.auth
state.isAdmin = data.root
}
},
actions: {
getPermission({ commit }) {
generateRoutes({ commit }) {
return new Promise((resolve, reject) => {
// apiConfigGetAuth()
// .then(data => {
// commit('setPermission', data)
// resolve(data)
// })
// .catch(err => {
// reject(err)
// })
resolve({})
apiConfigGetRoutes()
.then((data: any) => {
const rdata = JSON.parse(JSON.stringify(data))
const routes = filterAsyncRoutes(rdata)
commit('setSidebar', routes)
resolve(routes)
})
.catch(err => {
reject(err)
})
})
}
}

View File

@ -5,12 +5,14 @@ import { apiLogin, apiLogout, apiUserInfo } from '@/api/user'
export interface UserModule {
token: string
user: object
permissions: any[]
}
const user: Module<UserModule, any> = {
namespaced: true,
state: {
token: cache.get(TOKEN) || '',
user: {}
user: {},
permissions: []
},
mutations: {
setToken(state, data) {
@ -19,13 +21,15 @@ const user: Module<UserModule, any> = {
},
setUser(state, data) {
state.user = data
},
setPermission(state, permissions) {
state.permissions = permissions
}
},
actions: {
// 登录
login({ commit }, data) {
const { account, password } = data
console.log(data, '----------------------')
return new Promise((resolve, reject) => {
apiLogin({
@ -48,6 +52,7 @@ const user: Module<UserModule, any> = {
.then(data => {
commit('setToken', '')
commit('setUser', {})
commit('setPermission', [])
cache.remove(TOKEN)
resolve(data)
})
@ -60,8 +65,9 @@ const user: Module<UserModule, any> = {
getUser({ commit }) {
return new Promise((resolve, reject) => {
apiUserInfo()
.then(data => {
.then((data: any) => {
commit('setUser', data)
commit('setPermission', data.permissions)
resolve(data)
})
.catch(error => {

View File

@ -8,3 +8,5 @@
@import 'common';
// element样式
@import 'element';
// 动画
@import 'transition';

View File

@ -0,0 +1,27 @@
/* fade */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
transition: all .5s;
}
.fade-transform-enter {
opacity: 0;
transform: translateX(-25px);
}
.fade-transform-leave-to {
opacity: 0;
transform: translateX(25px);
}

View File

@ -0,0 +1,8 @@
/**
* @description id=1&name=2
* @param { String } str
* @returns { Boolean }
*/
export function isQuery(str: string) {
return /([^?&=]+)=([^?&=]*)/g.test(str)
}

View File

@ -117,6 +117,7 @@ export default defineComponent({
query: { redirect }
} = route
const path = typeof redirect === 'string' ? redirect : '/'
router.replace(path)
})
.catch(err => {

View File

@ -28,7 +28,7 @@
</el-card>
<el-card v-loading="pager.loading" class="m-t-15" shadow="never">
<router-link to="/permission/admin/edit">
<el-button type="primary" size="small">新增管理员</el-button>
<el-button v-perm="['system:admin:add']" type="primary" size="small">新增管理员</el-button>
</router-link>
<div class="m-t-15">
<el-table :data="pager.lists">
@ -69,6 +69,7 @@
<el-table-column label="操作" width="150" fixed="right">
<template #default="{ row }">
<router-link
v-perm="['system:admin:edit']"
class="m-r-10"
:to="{
path: '/permission/admin/edit',
@ -79,7 +80,7 @@
>
<el-button type="text">编辑</el-button>
</router-link>
<popup class="m-r-10 inline" @confirm="handleDelete(row.id)">
<popup v-perm="['system:admin:del']" class="m-r-10 inline" @confirm="handleDelete(row.id)">
<template #trigger>
<el-button type="text">删除</el-button>
</template>

View File

@ -2,7 +2,7 @@
<div class="menu">
<el-card shadow="never">
<router-link to="/permission/menu/edit">
<el-button type="primary" size="small">添加菜单</el-button>
<el-button v-perm="['system:menu:add']" type="primary" size="small">添加菜单</el-button>
</router-link>
<el-table
@ -36,6 +36,7 @@
<el-table-column label="操作">
<template #default="scope">
<router-link
v-perm="['system:menu:edit']"
class="m-r-10"
:to="{
path: '/permission/menu/edit',
@ -47,7 +48,7 @@
<el-button type="text" size="mini">编辑</el-button>
</router-link>
<popup class="m-r-10 inline" @confirm="handleDelete(scope.row.id)">
<popup v-perm="['system:menu:del']" class="m-r-10 inline" @confirm="handleDelete(scope.row.id)">
<template #trigger>
<el-button type="text" size="mini">删除</el-button>
</template>

View File

@ -2,7 +2,7 @@
<div class="role">
<el-card shadow="never">
<router-link to="/permission/role/edit">
<el-button type="primary" size="small">新增角色</el-button>
<el-button v-perm="['system:role:add']" type="primary" size="small">新增角色</el-button>
</router-link>
<div v-loading="pager.loading" class="m-t-15">
<div class="m-t-15">
@ -22,6 +22,7 @@
<template #default="{ row }">
<!-- 编辑 -->
<router-link
v-perm="['system:role:edit']"
class="m-r-10"
:to="{
path: '/permission/role/edit',
@ -33,7 +34,7 @@
<el-button type="text" size="mini">编辑</el-button>
</router-link>
<!-- 删除 -->
<popup class="m-r-10 inline" @confirm="handleDelete(row.id)">
<popup v-perm="['system:role:del']" class="m-r-10 inline" @confirm="handleDelete(row.id)">
<template #trigger>
<el-button type="text" size="mini">删除</el-button>
</template>