App.vue
<template>
<router-view></router-view>
</template>
<script setup>
</script>
<style scoped>
</style>
main.js
// import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import directives from "@/directives";
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(directives)
app.mount('#app')
views/LoginView.vue
<template>
<h1>用户登录</h1>
<div>
<input type="text" placeholder="用户名" v-model="state.username">
</div>
<div>
<input type="text" placeholder="密码" v-model="state.password">
</div>
<button @click="doLogin">登录</button>
</template>
<script setup>
import {reactive, ref} from "vue";
import {userInfoStore} from "@/stores/counter.js";
import {useRouter} from 'vue-router'
const store = userInfoStore()
const router = useRouter()
const state = reactive({
username: "root",
password: "123"
})
function doLogin(){
// 1. 向后端发送请求登录
// 2. 登陆成功
let response = {
token: "djfjwb-kfj-dsjvn",
username: "root",
role: "admin",
permission: {
"user-list": ["get", "post"],
"user-detail": ["get", "post", "put", "delete"],
"info-list": ["get", "post"]
}
}
// 3. 保存到localstorage和内存中
store.doLogin(response)
// 4. 重定向
router.push({name:"home"})
}
</script>
<style scoped>
</style>
views/AdminView.vue
<template>
<!-- <router-link :to="{name:'home'}">首页</router-link>-->
<!-- |-->
<!-- <router-link :to="{name:'user'}">用户中心</router-link>-->
<!-- |-->
<!-- <router-link :to="{name:'info'}">信息管理</router-link>-->
<!-- |-->
<!-- <router-link :to="{name:'video'}">视频管理</router-link>-->
<router-link v-for="item in menuRouterList" :to="{name:item.name}">{{ item.meta.title }}</router-link>
<router-view></router-view>
</template>
<script setup>
import {useRouter} from "vue-router"
import {computed} from "vue";
import {userInfoStore} from "@/stores/counter.js";
const router = useRouter()
const store = userInfoStore()
const menuRouterList = computed(() => {
// 1、获取所有路由
let totalRouterList = router.getRoutes()
// 2、删选出isMenu=true
return totalRouterList.filter((item) => {
let userRole = store.userRole
if (item.meta.isMenu && item.meta.role.indexOf(userRole) !== -1) {
return true
}
})
})
</script>
<style scoped>
</style>
views/admin/InfoView.vue
<template>
<h1>信息管理</h1>
<div>
<button v-if="hasPermission(['admin','manager', 'user'])">新增</button>
<button v-if="hasPermission(['admin','manager'])">编辑</button>
<button v-if="hasPermission(['admin','manager'])">删除</button>
</div>
<div>
<button v-if="hasPermission2('info-list','post')">新增2</button>
<button v-if="hasPermission2('info-detail','put')">编辑2</button>
<button v-if="hasPermission2('info-detail','delete')">删除2</button>
</div>
<div>
<button v-per="['admin','manager', 'user']">新增</button>
<button v-per="['admin','manager']">编辑</button>
<button v-per="['admin','manager']">删除</button>
</div>
<div>
<button v-per2="['info-list','post']">新增2</button>
<button v-per2="['info-detail','put']">编辑2</button>
<button v-per2="['info-detail','delete']">删除2</button>
</div>
</template>
<script setup>
import {hasPermission, hasPermission2} from "@/stores/permission.js"
</script>
<style scoped>
</style>
stores/counter.js
import {ref, computed} from 'vue'
import {defineStore} from 'pinia'
export const userInfoStore = defineStore('counter', () => {
const userString = ref(localStorage.getItem("userInfo") || null)
const userDict = computed(() => userString.value ? JSON.parse(userString.value) : null)
const userToken = computed(() => userDict.value ? userDict.value.token : null)
const userRole = computed(() => userDict.value ? userDict.value.role : null)
const userPermission = computed(() => userDict.value ? userDict.value.permission : null)
function doLogin(userInfo) {
// 放到内存
userString.value = JSON.stringify(userInfo)
// 写入LocalStorage
localStorage.setItem("userInfo", JSON.stringify(userInfo))
}
return {userPermission, userString, userToken, userRole, doLogin}
})
stores/permission.js
import {userInfoStore} from "@/stores/counter.js";
const store = userInfoStore()
export function hasPermission(allowRoleList) {
return allowRoleList.indexOf(store.userRole) !== -1
}
export function hasPermission2(name, method) {
const methodList = store.userPermission[name]
if (!methodList) {
return false;
}
return methodList.indexOf(method) !== -1;
}
router/index.js
import {createRouter, createWebHistory} from 'vue-router'
import {userInfoStore} from "@/stores/counter.js"
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
component: () => import('../views/AdminView.vue'),
children: [
{
path: 'home',
name: 'home',
component: () => import('../views/admin/HomeView.vue'),
meta: {isMenu: true, title: "首页", role: ["admin", "manager", "user"]}
},
{
path: 'user',
name: 'user',
component: () => import('../views/admin/UserView.vue'),
meta: {isMenu: true, title: "用户管理", role: ["admin", "manager"]}
},
{
path: 'info',
name: 'info',
component: () => import('../views/admin/InfoView.vue'),
meta: {isMenu: true, title: "信息管理", role: ["admin", "manager","user"]}
},
{
path: 'video',
name: 'video',
component: () => import('../views/admin/VideoView.vue'),
meta: {isMenu: true, title: "视频管理", role: ["admin", "user"]}
},
]
},
{
path: '/login',
name: 'login',
component: () => import('../views/LoginView.vue'),
},
],
})
router.beforeEach((to, from, next) => {
if (to.name === "login") {
next()
return;
}
const info = userInfoStore()
if (!info.userToken) {
next({"name": "login"})
return;
}
next()
})
export default router
directives/index.js
import per from './per'
import per2 from './per2'
const directives = {
per,
per2,
}
export default {
install(Vue) {
Object.keys(directives).forEach(key => {
Vue.directive(key, directives[key])
})
}
}
directives/per.js
import {userInfoStore} from "@/stores/counter.js";
export default {
mounted(element, bindings) {
let allowRoleList = bindings.value
let store = userInfoStore()
if (allowRoleList.indexOf(store.userRole) === -1) {
element.parentNode && element.parentNode.removeChild(element)
}
}
}
directives/per2.js
import {userInfoStore} from "@/stores/counter.js";
export default {
mounted(element, bindings) {
let [name, method] = bindings.value
const store = userInfoStore()
const methodList = store.userPermission[name]
if (!methodList) {
element.parentNode && element.parentNode.removeChild(element)
return
}
if (methodList.indexOf(method) === -1) {
element.parentNode && element.parentNode.removeChild(element)
}
}
}