权限控制
This commit is contained in:
parent
f20f1af16b
commit
143da05631
|
|
@ -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"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
}
|
||||
|
||||
/* 菜单 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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']`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,3 +17,4 @@ declare module 'nprogress' {
|
|||
export function start(): void
|
||||
export function done(): void
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ export interface AppModule {
|
|||
const app: Module<AppModule, any> = {
|
||||
namespaced: true,
|
||||
state: {
|
||||
config: {}
|
||||
// 公共配置
|
||||
config: {},
|
||||
},
|
||||
mutations: {
|
||||
setConfig(state, data) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -8,3 +8,5 @@
|
|||
@import 'common';
|
||||
// element样式
|
||||
@import 'element';
|
||||
// 动画
|
||||
@import 'transition';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* @description 判断字符串是否是id=1&name=2这种类型
|
||||
* @param { String } str
|
||||
* @returns { Boolean }
|
||||
*/
|
||||
export function isQuery(str: string) {
|
||||
return /([^?&=]+)=([^?&=]*)/g.test(str)
|
||||
}
|
||||
|
|
@ -117,6 +117,7 @@ export default defineComponent({
|
|||
query: { redirect }
|
||||
} = route
|
||||
const path = typeof redirect === 'string' ? redirect : '/'
|
||||
|
||||
router.replace(path)
|
||||
})
|
||||
.catch(err => {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue