赞
踩
描述 | 地址 |
源码地址 | springboot3.0+spring security6+vue3 前后分离: springboot3.0+spring security6+vue3 前后分离 |
springboot3.0+spring security6+vue3 前后分离之后端部分 | springboot3.0+spring security6+vue3 前后分离之后端部分-CSDN博客 |
npm create vite
输入项目的名字
选中vue
选择TypeScript
进入项目目录
npm install
启动项目
浏览器访问
npm i axios
npm i element-plus @element-plus/icons-vue
npm i vue-router
npm i pinia
- declare module "*.vue" {
- import Vue from "vue";
- export default Vue;
- }
配置跨域
- import { defineConfig } from 'vite'
- import vue from '@vitejs/plugin-vue'
- import path from 'path'
-
- // https://vitejs.dev/config/
- export default defineConfig({
- plugins: [vue()],
- resolve:{
- alias:{
- //相对路径别名配置 用@符号替代src
- "@": path.resolve("./src")
- }
- },
- server: {
- proxy: {
- '/sp': {
- target: 'http://localhost:8083/',
- changeOrigin: true,
- //把api前置去掉
- rewrite: (path) => path.replace(/^\/sp/, "")
- }
- }
- }
- })
- {
- "compilerOptions": {
- "target": "ES2020",
- "useDefineForClassFields": true,
- "module": "ESNext",
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "skipLibCheck": true,
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
- "jsx": "preserve",
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
- //解析非相对模块的基地址,默认是当前目录
- "baseUrl": "./",
- "paths": {
- //路径映射,相当于baseUrl
- "@/*":["src/*"]
- }
- },
- "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue","vue.d.ts"],
- "references": [{ "path": "./tsconfig.node.json" }]
- }
- #测试环境标识
- NODE_ENV="dev"
- VITE_APP_TITLE="应用标题"
- #基础路径
- VITE_APP_BASE_API="http://localhost:8083"
- #后端服务器的域名
- VITE_SERVE="http://aa.com"
拦截所有路径
- //引入路由器
- import router from '@/router/index'
- //引入小仓库
- import loginStore from "@/store/modules/login";
- //引入大仓库
- import pinia from "@/store/index.ts";
- //获取小仓库对象
- let lgst=loginStore(pinia);
-
- //全局前置路由守卫,任意路由切换都会触发钩子
- router.beforeEach((to,from,next)=>{
-
- //console.log(to.path)
- //如果是从login进来
- if(to.path=='/login'){
- //放行往下走
- next()
- }else{
- //判断是否存在token
- if(!lgst.token){
- //如果未登录,直接跳到登录界面
- next('/login')
- }else{
- //获取登录用户权限信息
- let res=lgst.useMyAuth();
- // console.log('path', to.path);
- // console.log('auth', to.meta.auth);
- // console.log('to', to);
- res.then((x)=>{
- if(!to.meta.auth){
- //如果权限是空的 也放行
- next()
- }else if(x.indexOf(to.meta.auth)!==-1){
- //如果登录了 权限也有放行
- next()
- }else{
- //如果都不满足 调到无权限界面
- next('/per')
- }
- })
- }
- }
- })
-
- //全局后置守卫
- router.afterEach((to,from)=>{
-
- })
-
入口文件
- import { createApp } from 'vue'
- import App from './App.vue'
- import ElementPlus from 'element-plus'
- import 'element-plus/dist/index.css'
- //国际化
- //@ts-ignore 忽略当前ts文件报红的错误,不设置这个在打包的时候会报错
- import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
- //引入element-plus的icons
- import * as ElementPlusIconsVue from '@element-plus/icons-vue'
- //引入路由
- import router from './router/index'
- //引入大仓库
- import pinia from './store/index'
- //引入全局路由守卫
- import '@/permisstion.ts'
-
- const app = createApp(App)
-
- //使用ElementPlus,并设置国际化
- app.use(ElementPlus, {
- locale: zhCn,
- })
-
- //使用路由
- app.use(router)
-
- //使用大仓库
- app.use(pinia)
-
- //全局注册icon图标
- for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
- app.component(key, component)
- }
-
- //挂载到app上
- app.mount('#app')
- <template>
- <div>
- <router-view></router-view>
- </div>
- </template>
-
- <script setup lang="ts">
-
-
- </script>
-
- <style scoped>
-
- </style>
后端接口文件
- import request from "@/utils/request";
- //统一管理接口
- enum API{
- //登录后端接口
- LOGIN="/dengLu",
- //获取当前登录人的菜单
- GET_MY_MENU_LIST="/getMyMenuList",
- //获取当前登录人的权限
- GET_MY_AUTH="/getMyAuth",
- //获取所有用户
- GET_USER_LIST="/getUserList",
- //获取所有角色
- GET_ROLE_LIST="/getRoleList",
- //获取所有菜单
- GET_MENU_LIST="/getMenuList",
-
- //添加用户
- ADD_USER="/addUser",
- //获取当前登录人信息
- GET_USER_INFO="/getUserInfo",
- //为用户分配角色
- SET_USER_ROLE="/setUserRole",
- //查看用户对应的角色id
- GET_USER_ROLE_IDS="/getUserRoleIds",
-
- //添加角色
- ADD_ROLE="/addRole",
- //修改角色
- EDIT_ROLE="/editRole",
- //删除角色
- DELETE_ROLE="/deleteRole",
-
- //添加菜单
- ADD_MENU="/addMenu",
- //修改菜单
- EDIT_MENU="/editMenu",
- //删除菜单
- DELETE_MENU="/deleteMenu",
-
- //查看角色对应的权限
- GET_ROLE_AUTH="/getRoleAuth",
- //为角色分配权限
- SET_ROLE_AUTH="/setRoleAuth",
-
-
- }
-
-
- //登录接口方法
- export const reqLogin=(data:any)=> request.post<any,any>(API.LOGIN,data)
- //获取当前登录人的菜单
- export const getMyMenuList=()=> request.post<any>(API.GET_MY_MENU_LIST)
- //获取当前登录人的权限
- export const getMyAuth=()=> request.post<any>(API.GET_MY_AUTH)
- //获取所有用户
- export const getUserList=()=> request.post<any>(API.GET_USER_LIST)
- //获取所有角色
- export const getRoleList=()=> request.post<any>(API.GET_ROLE_LIST)
- //获取所有菜单
- export const getMenuList=()=> request.post<any>(API.GET_MENU_LIST)
-
-
- //添加用户
- export const addUser=(data:any)=> request.post<any>(API.ADD_USER,data)
- //获取当前登录人信息
- export const getUserInfo=()=> request.post<any>(API.GET_USER_INFO)
- //为用户分配角色
- export const setUserRole=(data:any)=> request.post<any>(API.SET_USER_ROLE,data)
- //查看用户对应的角色id
- export const getUserRoleIds=(data:any)=> request.post<any>(API.GET_USER_ROLE_IDS,data)
-
-
- //添加角色
- export const addRole=(data:any)=> request.post<any>(API.ADD_ROLE,data)
- //修改角色
- export const editRole=(data:any)=> request.post<any>(API.EDIT_ROLE,data)
- //删除角色
- export const deleteRole=(data:any)=> request.post<any>(API.DELETE_ROLE,data)
-
-
- //添加菜单
- export const addMenu=(data:any)=> request.post<any>(API.ADD_MENU,data)
- //修改菜单
- export const editMenu=(data:any)=> request.post<any>(API.EDIT_MENU,data)
- //删除菜单
- export const deleteMenu=(data:any)=> request.post<any>(API.DELETE_MENU,data)
-
- //查看角色对应的权限
- export const getRoleAuth=(data:any)=> request.post<any>(API.GET_ROLE_AUTH,data)
-
- //为角色分配权限
- export const setRoleAuth=(data:any)=> request.post<any>(API.SET_ROLE_AUTH,data)
- //通过vue-router插件实现模版路由配置
- import { createRouter,createWebHashHistory } from 'vue-router';
- //引入路由数组
- import {luYou} from '@/router/routers'
- //创建路由器
- const router=createRouter({
- //路由模式
- history: createWebHashHistory(),
- //注意单词 别写错了
- //注意单词 别写错了
- routes: luYou
- })
-
- export default router;
路由数组 就是往那个vue界面去跳转
- //单独暴露路由
- export const luYou=[
- {
- path:'/login',
- component:()=> import('@/views/login/index.vue'),
- name:'login',
- meta:{
- //隐藏不显示到菜单上 true:隐藏 ,false:显示
- hidden:true,
- //菜单的名称
- title:'login',
- //饿了么ui图标的名字 固定写法
- icon:'Plus',
- auth:''
- }
- },
- {
- path:'/per',
- component:()=> import('@/views/per/index.vue'),
- name:'per',
- meta:{
- hidden:true,
- title:'per',
- icon:'Plus',
- auth:''
- }
- },
- {
- path:'/404',
- component:()=> import('@/views/404/index.vue'),
- name:'404',
- meta:{
- hidden:true,
- title:'404',
- icon:'Plus',
- auth:''
- }
- },
- {
- //根页面
- path:'/',
- component:()=> import('@/views/menu/index.vue'),
- name:'menu',
- meta:{
- hidden:true,
- title:'login',
- icon:'Plus',
- auth:''
- }
- },
- {
- //匹配到不存在的路径就跳转404
- path:'/:pathMatch(.*)*',
- //重定向到404
- redirect: '/404',
- //任意路由
- name:'any',
- meta:{
- hidden:true,
- title:'any',
- icon:'Plus',
- auth:''
- }
- },
- {
- path:'/org',
- component:()=> import('@/views/menu/index.vue'),
- name:'org',
- meta:{
- hidden:true,
- title:'组织管理',
- icon:'Plus',
- auth:'org'
- },
- children:[
- {
- path:'/org/er',
- component:()=> import('@/views/org/index.vue'),
- name:'orgEr',
- meta:{
- hidden:true,
- title:'组织管理二级菜单',
- icon:'Plus',
- auth:'org:er'
- }
- }
- ]
- },
- {
- path:'/user',
- component:()=> import('@/views/menu/index.vue'),
- name:'user',
- meta:{
- hidden:true,
- title:'用户管理',
- icon:'Plus',
- auth:'user'
- },
- children:[
- {
- path:'/user/er',
- component:()=> import('@/views/user/index.vue'),
- name:'userEr',
- meta:{
- hidden:true,
- title:'用户管理二级菜单',
- icon:'Plus',
- auth:'user:er'
- }
- }
- ]
- },
- {
- path:'/role',
- component:()=> import('@/views/menu/index.vue'),
- name:'role',
- meta:{
- hidden:true,
- title:'角色管理',
- icon:'Plus',
- auth:'role'
- },
- children:[
- {
- path:'/role/er',
- component:()=> import('@/views/role/index.vue'),
- name:'roleEr',
- meta:{
- hidden:true,
- title:'角色管理二级菜单',
- icon:'Plus',
- auth:'role:er'
- }
- }
- ]
- },
- {
- path:'/auth',
- component:()=> import('@/views/menu/index.vue'),
- name:'auth',
- meta:{
- hidden:true,
- title:'权限管理',
- icon:'Plus',
- auth:'auth'
- },
- children:[
- {
- path:'/auth/er',
- component:()=> import('@/views/auth/index.vue'),
- name:'authEr',
- meta:{
- hidden:true,
- title:'权限管理二级菜单',
- icon:'Plus',
- auth:'auth:er'
- }
- }
- ]
- },
- {
- path:'/apply',
- component:()=> import('@/views/menu/index.vue'),
- name:'apply',
- meta:{
- hidden:true,
- title:'应用管理',
- icon:'Plus',
- auth:'apply'
- },
- children:[
- {
- path:'/apply/er',
- component:()=> import('@/views/apply/index.vue'),
- name:'applyEr',
- meta:{
- hidden:true,
- title:'应用管理二级菜单',
- icon:'Plus',
- auth:'apply:er'
- }
- }
- ]
- },
- ]
- //创建用户相关的小仓库
- import {defineStore} from 'pinia'
- //引入接口
- import { reqLogin,getUserInfo,getMyAuth } from '../../api/index';
-
-
- //创建登录小仓库
- let loginStore=defineStore('login',{
- //小仓库存储数据的地方
- state:()=>{
- return {
- //从本地拿到token
- token: localStorage.getItem('TOKEN'),
- //当前登录人姓名
- name:'',
- }
- },
- //异步| 逻辑处理的地方,在方法前面定义async,那么必须在拿到对应的方法前面加await 一起使用
- actions:{
- async userLogin(data: any){
- //拿到登录后的结果
- let res:any=await reqLogin(data);
- if(res){
- let code=res.code;
- let msg=res.msg;
- let data=res.data;
- if(code=='200'){
- //刷新token
- this.token=data;
- //把token放入本地
- localStorage.setItem('TOKEN',data);
- return 'ok';
- }else{
- //失败返回失败对象
- return Promise.reject(Error(msg))
- }
- }else{
- //失败返回失败对象
- return Promise.reject(Error('账号密码输入错误'))
- }
-
- },
- async userInfo(){
- //登录后获取用户信息 请求头自带token
- let res=await getUserInfo();
- this.name=res.data.name;
- },
- userLogout(){
- //退出登录 清空用户信息 和token
- this.token=''
- this.name=''
- localStorage.removeItem('TOKEN');
- },
- async useMyAuth(){
- //登录后获取用户信息 请求头自带token
- let res=await getMyAuth();
- return res.data;
- },
- },
- getters:{
-
- }
- })
- //对外暴露小仓库的方法
- export default loginStore;
- //创建用户相关的小仓库
- import {defineStore} from 'pinia'
- //引入路由数组
- import {luYou} from '@/router/routers'
- //引入接口
- import { getMyAuth } from '../../api/index';
-
- //创建小仓库
- let luYouStore=defineStore('luYou',{
- //小仓库存储数据的地方
- state:()=>{
- return {
- //路由
- ly:[]
- }
- },
- //异步| 逻辑处理的地方,在方法前面定义async,那么必须在拿到对应的方法前面加await 一起使用
- actions:{
- async useMyMenuList(){
- //获取当前登录人的权限集合
- let res=await getMyAuth();
- let auths=res.data;
- //赋值给新的数组
- let newLy = luYou.map(x => {
-
- if(auths.indexOf(x.meta.auth) !== -1){
- //如果路径匹配 那么设置为显示菜单
- x.meta.hidden=false
- }
- let children=x.children;
- if(children){
- children.map(y=>{
- if(auths.indexOf(y.meta.auth) !== -1){
- //如果路径匹配 那么设置为显示菜单
- y.meta.hidden=false
- }
- return y;
- })
- }
-
- return x;
- });
-
- //更新state的数据
- this.ly=newLy;
-
- }
- },
- getters:{
-
- }
- })
- //对外暴露小仓库的方法
- export default luYouStore;
- //引入pinia
- import {createPinia} from 'pinia'
- //创建大仓库
- let pinia=createPinia();
- //暴露大仓库 入口文件需要安装仓库
- export default pinia;
axios 二次封装 请求头 自动带token
- import axios from "axios";
- //引入消息提示
- import {ElMessage} from 'element-plus';
- //引入登录小仓库
- import loginStore from "@/store/modules/login";
-
- //利用axios对象的create方法,去创建axios实例
- let request=axios.create({
- //基础路径 自动带上前缀
- baseURL: import.meta.env.VITE_APP_BASE_API,
- //超时时间,超过时间就获取不到后端的数据了
- timeout: 5000
- })
- //request实例添加请求拦截器
- request.interceptors.request.use((config)=>{
- let lgst=loginStore();
- if(lgst.token){
- //config配置对象,headers属性请求头,给后台携带公共参数
- //设置token 放到请求头上
- config.headers['Authorization']='Bearer '+lgst.token;
- }
- //console.log('请求拦截器:',config)
- return config;
- })
- //添加响应拦截器
- request.interceptors.response.use((response)=>{
- //成功回调
- //console.log('响应拦截器:',response)
- return response.data;
- },(error)=>{
- //http状态码
- //console.log('错误状态:',error.response)
- if(error.response==undefined){
- ElMessage({
- type:'error',
- message:'网络异常'
- })
- }else{
- ElMessage({
- type:'error',
- message:error.response.data.msg
- })
- }
-
- //返回一个失败的Promise对象
- return Promise.reject(error);
- })
-
- //对外暴露 才能被外部使用
- export default request;
- <template>
- <div>
- 我是404
- </div>
- </template>
-
- <script>
- export default {
-
- }
- </script>
-
- <style>
-
- </style>
- <template>
- 我是应用
- </template>
-
- <script>
- export default {
-
- }
- </script>
-
- <style>
-
- </style>
- <template>
- <div>
- <el-card class="box-card">
- <template #header>
- <div class="card-header">
- <span>权限管理</span>
- </div>
- </template>
- <el-button type="primary" icon="Plus" @click="add(0,'1')" v-if="authErAdd">添加一级菜单</el-button>
-
- <el-table
- :data="tableData"
- style="width: 100%; margin-bottom: 20px"
- row-key="id"
- border
- default-expand-all
- >
- <el-table-column prop="name" label="菜单名称/按钮名称" sortable width="200"/>
- <el-table-column prop="auth" label="权限名称" sortable width="180"/>
- <el-table-column prop="path" label="路径" sortable width="180"/>
- <el-table-column prop="createTime" label="创建时间" sortable width="180"/>
- <el-table-column prop="desc" label="备注" sortable width="180"/>
- <el-table-column
- prop="isType"
- label="类型"
- width="180"
- >
- <template #default="scope">
- <el-tag v-if="scope.row.isType=='1'">
- 菜单
- </el-tag>
- <el-tag v-if="scope.row.isType=='2'">
- 按钮
- </el-tag>
-
- </template>
- </el-table-column>
-
- <el-table-column prop="caozuo" label="操作">
- <!--具名插槽-->
- <template #default="caozuo">
-
- <!--一级菜单 可以添加二级菜单-->
- <el-button type="primary" icon="plus" v-if="authErAddSub && caozuo.row.isType=='1' && caozuo.row.parentId==0" @click="add(caozuo.row.id,'1')">添加二级菜单</el-button>
- <!--二级菜单 可以添加按钮-->
- <el-button type="primary" icon="plus" v-if="authErBtn && caozuo.row.isType=='1' && caozuo.row.parentId!=0" @click="add(caozuo.row.id,'2')">添加按钮</el-button>
- <el-button type="primary" v-if="authErEdit" icon="edit" @click="edit(caozuo.row)">修改</el-button>
- <el-button type="primary" v-if="authErDel" icon="delete" @click="del(caozuo.row.id)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- </el-card>
-
-
- <!--点击新增弹出对话框-->
- <el-dialog
- v-model="dialogVisible"
- title="添加"
- width="30%"
- :before-close="handleClose"
- >
- <el-form :model="addBean">
- <el-form-item label="父级id" >
- <el-input label-width="80%" v-model="addBean.parentId" disabled/>
- </el-form-item>
- <el-form-item label="名称" >
- <el-input label-width="80%" v-model="addBean.name"/>
- </el-form-item>
- <el-form-item label="权限名称" >
- <el-input label-width="80%" v-model="addBean.auth"/>
- </el-form-item>
- <el-form-item label="路径" >
- <el-input label-width="80%" v-model="addBean.path"/>
- </el-form-item>
- <el-form-item label="排序" >
- <el-input-number :min="1" :max="1000" v-model="addBean.paiXu" />
- </el-form-item>
- <el-form-item label="类型" >
- <el-select v-model="addBean.isType" disabled>
- <el-option
- v-for="item in options"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- </el-form>
-
- <!--底部插槽-->
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="dialogVisible = false">取消</el-button>
- <el-button type="primary" @click="insert">确定</el-button>
- </span>
- </template>
- </el-dialog>
-
- <!--点击修改弹出对话框-->
- <el-dialog
- v-model="editDialog"
- title="修改"
- width="30%"
- :before-close="handleClose"
- >
- <el-form :model="updateBean">
- <el-form-item label="菜单id">
- <el-input label-width="80%" v-model="updateBean.id" disabled/>
- </el-form-item>
- <el-form-item label="名称" >
- <el-input label-width="80%" v-model="updateBean.name"/>
- </el-form-item>
- <el-form-item label="权限名称" >
- <el-input label-width="80%" v-model="updateBean.auth"/>
- </el-form-item>
- <el-form-item label="路径" >
- <el-input label-width="80%" v-model="updateBean.path"/>
- </el-form-item>
- <el-form-item label="排序" >
- <el-input-number :min="1" :max="1000" v-model="updateBean.paiXu" />
- </el-form-item>
- <el-form-item label="类型" >
- <el-select v-model="updateBean.isType" disabled>
- <el-option
- v-for="item in options"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- </el-form>
-
- <!--底部插槽-->
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="editDialog = false">取消</el-button>
- <el-button type="primary" @click="update">确定</el-button>
- </span>
- </template>
- </el-dialog>
-
- </div>
- </template>
-
- <script setup lang="ts">
- import {ref,onMounted,reactive} from 'vue'
- //引入后端接口
- import {getMenuList,addMenu,editMenu,deleteMenu,getMyAuth} from '@/api/index'
-
- //引入提示
- import { ElMessage,ElMessageBox } from 'element-plus'
- import { fa } from 'element-plus/es/locale/index.mjs';
-
- //表格数据
- let tableData=ref([]);
-
- //获取分页数据
- let getData=async ()=>{
- //必须异步阻塞去获取 否则拿到的就是一个Promise对象
- let res=await getMenuList();
- tableData.value=res.data;
- }
-
- //加载时调用
- onMounted(()=>{
- //调用查询
- getData();
- //获取按钮权限
- getAuthData();
- })
-
- //下拉框内容
- const options = [
- {
- value: '1',
- label: '菜单',
- },
- {
- value: '2',
- label: '按钮',
- }
- ]
-
-
- //----------------------添加-----------------------
-
- //修改对象
- let addBean=reactive({
- parentId:null,
- name:'',
- auth:'',
- isType:'',
- paiXu:'',
- path:''
- })
- //默认不显示对话框
- let dialogVisible=ref(false)
- //添加显示对话框
- let add=(parentId,isType)=>{
- //显示对话框
- dialogVisible.value=true;
-
- //把输入框显示的内容清空
- addBean.parentId=parentId;
- addBean.name='';
- addBean.auth='';
- addBean.isType=isType;
- addBean.paiXu='';
- addBean.path='';
- }
-
- //添加权限 调用后端接口
- let insert= async ()=>{
- //调用后端添加品牌方法
- let res=await addMenu(addBean);
- console.log(res);
- if(res.code=='200'){
- //执行成功后关闭对话框
- dialogVisible.value=false;
- ElMessage.success('添加成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- }
-
- //----------------------删除-----------------------
- let del=async (id)=>{
- await ElMessageBox.confirm(
- '确定删除吗?',
- '删除',
- {
- confirmButtonText: 'OK',
- cancelButtonText: 'Cancel',
- type: 'warning',
- }
- )
- .then(() => {
- deleteMenu({
- id:id
- }).then((res)=>{
- if(res.code=='200'){
- ElMessage.success('删除成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- })
-
-
- })
- .catch(() => {
-
- })
-
-
-
- }
-
-
- //----------------------修改-----------------------
-
- //修改对象
- let updateBean=reactive({
- id:null,
- name:'',
- auth:'',
- isType:'',
- paiXu:'',
- path:''
- })
- //默认不显示对话框
- let editDialog=ref(false)
- //显示对话框
- let edit=(row)=>{
- //显示对话框
- editDialog.value=true;
-
- //把输入框显示内容赋值
- updateBean.id=row.id;
- updateBean.name=row.name;
- updateBean.auth=row.auth;
- updateBean.isType=row.isType;
- updateBean.paiXu=row.paiXu;
- updateBean.path=row.path;
- }
-
- //修改权限 调用后端接口
- let update= async ()=>{
- //调用后端添加品牌方法
- let res=await editMenu(updateBean);
- if(res.code=='200'){
- //执行成功后关闭对话框
- editDialog.value=false;
- ElMessage.success('修改成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- }
-
- //--------------------------按钮显示隐藏----------------------------
- //按钮权限
- //添加一级菜单按钮默认不显示
- let authErAdd=ref(false);
- //添加二级菜单按钮默认不显示
- let authErAddSub=ref(false);
- //修改按钮默认不显示
- let authErEdit=ref(false);
- //删除按钮默认不显示
- let authErDel=ref(false);
- //添加子级按钮 默认不显示
- let authErBtn=ref(false);
-
- let getAuthData= async()=>{
- //获取菜单权限
- let res=await getMyAuth();
- //如果存在对应的权限 才显示按钮
- if(res.data.indexOf('auth:er:add')!==-1){
- authErAdd.value=true;
- }
- if(res.data.indexOf('auth:er:del')!==-1){
- authErDel.value=true;
- }
- if(res.data.indexOf('auth:er:edit')!==-1){
- authErEdit.value=true;
- }
- if(res.data.indexOf('auth:er:add:sub')!==-1){
- authErAddSub.value=true;
- }
- if(res.data.indexOf('auth:er:btn')!==-1){
- authErBtn.value=true;
- }
-
-
- }
-
- </script>
-
- <style scoped>
-
- </style>
-
- <style>
-
- </style>
- <template>
- <div>
- 我是首页
- </div>
- </template>
-
- <script>
- export default {
-
- }
- </script>
-
- <style>
-
- </style>
- <template>
-
- <el-card class="box-card">
- <template #header>
- <div class="card-header">
- <span>权限管理系统</span>
-
- </div>
-
- </template>
- <el-form
- ref="ruleFormRef"
- :model="ruleForm"
- :rules="rules"
- label-width="120px"
-
- >
- <el-form-item label="账号" prop="account">
- <el-input v-model="ruleForm.account" />
- </el-form-item>
-
- <el-form-item label="密码" prop="password">
- <el-input
- v-model="ruleForm.password"
- type="password"
- placeholder="请输入密码"
- show-password
- />
- </el-form-item>
-
- <el-form-item>
- <el-button type="primary" @click="login()">
- 登录
- </el-button>
- </el-form-item>
-
- </el-form>
- </el-card>
-
-
-
-
- </template>
-
- <script lang="ts" setup>
- import { reactive, ref } from 'vue'
- import type { FormInstance, FormRules } from 'element-plus'
- import { ElMessage } from 'element-plus'
- //引入路由
- import {useRouter} from 'vue-router'
- //引入登录小仓库
- import loginStore from '../../store/modules/login.ts';
-
-
- //定义接口
- interface RuleForm {
- account: string
- password: string
- }
-
- //获取路由器
- let router=useRouter();
-
-
- const ruleFormRef = ref<RuleForm>()
- //使用接口 并且 为每一个文本框赋 默认值
- const ruleForm = reactive<RuleForm>({
- account: 'user',
- password: '123456'
- })
-
- //校验文本框的内容
- const rules = reactive<FormRules<RuleForm>>({
- account: [
- { required: true, message: '账号不能为空', trigger: 'blur' },
- { min: 3, max: 10, message: '长度在3到10之间', trigger: 'blur' },
- ],
- password: [
- {
- required: true,
- message: '密码不能为空',
- trigger: 'change',
- },
- ]
- })
-
-
-
- //登录方法
- let login= async ()=>{
- //阻塞form 表单的校验 必须完成之后才能往下走 因为validate是一个async方法
- await ruleFormRef.value.validate();
- try {
- //阻塞拿到结果才往下走
- await loginStore().userLogin(ruleForm);
- //弹框
- ElMessage({
- showClose: true,
- message: '登录成功',
- type: 'success',
- })
- //跳转根路径
- router.push("/")
- } catch (error) {
- ElMessage({
- showClose: true,
- message: (error as Error).message,
- type: 'error',
- })
- }
- }
-
- </script>
- <template>
- <div>
- <el-row>
-
- <el-col :span="3">
- <!--显示左侧菜单-->
- <!--组件传参 把菜单数组传过去-->
- <Sub :menuList="lyst.ly"></Sub>
- </el-col>
-
-
- <el-col :span="21">
- <div>
- <el-row>
- <el-col :span="21"></el-col>
- <el-col :span="3">
- <!--显示用户信息-->
- 当前登录人:{{ lgStore.name }}
- <el-button type="primary" @click="logout">退出登录</el-button>
- </el-col>
- </el-row>
-
- </div>
- <div>
- <!--显示菜单点击后的内容-->
- <router-view></router-view>
- </div>
- </el-col>
-
-
- </el-row>
- </div>
-
-
- </template>
-
- <script lang="ts" setup>
- import Sub from '@/views/sub/index.vue'
- //引入小仓库
- import luYouStore from '@/store/modules/luyou';
- import { onMounted } from 'vue';
- //引入路由
- import {useRouter} from 'vue-router'
- //引入登录小仓库
- import loginStore from '../../store/modules/login.ts';
-
- //获取路由器
- let router=useRouter();
-
- //使用小仓库
- let lyst=luYouStore()
-
-
- //拿到登录仓库对象
- let lgStore=loginStore();
-
- //生命周期挂载
- onMounted(()=>{
- //初始化菜单
- lyst.useMyMenuList();
- //获取用户信息
- lgStore.userInfo();
-
- })
-
-
- //退出登录
- let logout=()=>{
- loginStore().userLogout()
- //退出后跳转到登录界面
- router.push('/login')
- }
-
- </script>
-
- <style scoped>
-
- </style>
- <template>
- 我是组织架构
- </template>
-
- <script>
- export default {
-
- }
- </script>
-
- <style>
-
- </style>
- <template>
- <h1>
- 无权限
- </h1>
- </template>
-
- <script>
- export default {
-
- }
- </script>
-
- <style>
-
- </style>
- <template>
- <div>
- <el-card class="box-card">
- <template #header>
- <div class="card-header">
- <span>角色管理</span>
- </div>
- </template>
- <el-button type="primary" icon="Plus" @click="add" v-if="roleErAdd">添加</el-button>
- <el-table :data="tableData" style="width: 100%" >
- <el-table-column label="序号" width="180" type="index"/>
- <el-table-column prop="roleCode" label="角色编码" width="180" />
- <el-table-column prop="roleName" label="角色名称" width="180" />
- <el-table-column prop="caozuo" label="操作">
- <!--具名插槽-->
- <template #default="caozuo">
- <el-button type="primary" icon="edit" @click="edit(caozuo.row)" v-if="roleErEdit">修改</el-button>
- <el-button type="primary" icon="delete" @click="del(caozuo.row.id)" v-if="roleErDel">删除</el-button>
- <el-button type="primary" icon="Setting" @click="dakai(caozuo.row.id)" v-if="roleErFp">分配权限</el-button>
- </template>
- </el-table-column>
- </el-table>
-
-
- </el-card>
-
-
- <!--点击新增按钮弹出对话框-->
- <el-dialog
- v-model="dialogVisible"
- title="添加"
- width="30%"
- :before-close="handleClose"
- >
- <el-form :model="addBean">
- <el-form-item label="角色编码" >
- <el-input label-width="80%" v-model="addBean.roleCode"/>
- </el-form-item>
- <el-form-item label="角色名称" >
- <el-input label-width="80%" v-model="addBean.roleName"/>
- </el-form-item>
- </el-form>
-
- <!--底部插槽-->
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="dialogVisible = false">取消</el-button>
- <el-button type="primary" @click="insert">确定</el-button>
- </span>
- </template>
- </el-dialog>
-
-
-
- <!--点击修改按钮弹出对话框-->
- <el-dialog
- v-model="editDialog"
- title="修改"
- width="30%"
- :before-close="handleClose"
- >
- <el-form :model="updateBean">
- <el-form-item label="角色id" >
- <el-input label-width="80%" v-model="updateBean.id" disabled/>
- </el-form-item>
- <el-form-item label="角色编码" >
- <el-input label-width="80%" v-model="updateBean.roleCode"/>
- </el-form-item>
- <el-form-item label="角色名称" >
- <el-input label-width="80%" v-model="updateBean.roleName"/>
- </el-form-item>
- </el-form>
-
- <!--底部插槽-->
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="editDialog = false">取消</el-button>
- <el-button type="primary" @click="update">确定</el-button>
- </span>
- </template>
- </el-dialog>
-
-
- <!--点击分配权限按钮弹出对话框-->
-
- <el-dialog
- v-model="fpDialog"
- title="分配权限"
- width="30%"
- :before-close="handleClose"
- >
- <el-tree
- ref="tree"
- :data="data"
- show-checkbox
- node-key="id"
- default-expand-all
- :default-checked-keys="checkedArr"
- :props="defaultProps"
- >
- </el-tree>
- <el-button @click="fpDialog = false">取消</el-button>
- <el-button type="success" @click="fpAuth">确定</el-button>
- </el-dialog>
-
- </div>
- </template>
-
- <script setup lang="ts">
- import {ref,onMounted,reactive} from 'vue'
- //引入后端接口
- import {getRoleList,addRole,deleteRole,editRole,getMenuList,getRoleAuth,setRoleAuth,getMyAuth} from '@/api/index'
- import { ElMessage, ElMessageBox } from 'element-plus'
-
- //----------------------查询-----------------------
- //表格数据
- let tableData=ref([]);
-
- //获取分页数据
- let getData=async ()=>{
- //必须异步阻塞去获取 否则拿到的就是一个Promise对象
- let res=await getRoleList();
- tableData.value=res.data;
- }
-
- //加载时调用
- onMounted(()=>{
- //调用查询
- getData();
- //获取按钮权限
- getAuthData();
- })
-
- //----------------------添加-----------------------
-
- //添加对象
- let addBean=reactive({
- roleCode:'',
- roleName:''
- })
- //默认不显示对话框
- let dialogVisible=ref(false)
- //添加显示对话框
- let add=()=>{
- //显示对话框
- dialogVisible.value=true;
-
- //把输入框显示的内容清空
- addBean.roleCode='';
- addBean.roleName='';
- }
-
- //添加角色 调用后端接口
- let insert= async ()=>{
- //调用后端添加品牌方法
- let res=await addRole(addBean);
- console.log(res);
- if(res.code=='200'){
- //执行成功后关闭对话框
- dialogVisible.value=false;
- ElMessage.success('添加成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- }
-
- //----------------------修改-----------------------
-
- //修改对象
- let updateBean=reactive({
- id:null,
- roleCode:'',
- roleName:''
- })
- //默认不显示对话框
- let editDialog=ref(false)
- //显示对话框
- let edit=(row)=>{
- //显示对话框
- editDialog.value=true;
-
- //把输入框显示内容赋值
- updateBean.id=row.id;
- updateBean.roleCode=row.roleCode;
- updateBean.roleName=row.roleName;
-
- }
-
- //修改角色 调用后端接口
- let update= async ()=>{
- //调用后端添加品牌方法
- let res=await editRole(updateBean);
- console.log(res);
- if(res.code=='200'){
- //执行成功后关闭对话框
- editDialog.value=false;
- ElMessage.success('修改成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- }
-
- //----------------------删除-----------------------
- let del=async (id)=>{
- await ElMessageBox.confirm(
- '确定删除吗?',
- '删除',
- {
- confirmButtonText: 'OK',
- cancelButtonText: 'Cancel',
- type: 'warning',
- }
- )
- .then(() => {
- deleteRole({
- id:id
- }).then((res)=>{
- if(res.code=='200'){
- ElMessage.success('删除成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- })
-
-
- })
- .catch(() => {
-
- })
-
-
-
- }
-
-
-
- //----------------------分配权限-----------------------
- const fpDialog = ref(false)
-
-
- //定义后端的显示字段
- const defaultProps = {
- children: 'children',
- label: 'name',
- }
-
- //显示的数组
- let data=ref([])
-
- //选中的数组
- let checkedArr=ref([])
-
- //选中的树的id数组
- let tree=ref([])
-
- //分配权限 那一列的 角色id
- let authRoleId=ref()
-
- //打开树
- let dakai=async(id)=>{
- //先把选择的清空掉
- checkedArr.value=null;
- //调用后端权限方法
- let res=await getMenuList();
- if(res.code=='200'){
- data.value=res.data;
- //赋值给角色id
- authRoleId.value=id;
- //获取当前角色对应的权限
- getRoleAuth({
- roleId:id
- }).then((auths)=>{
- //选中的数组赋值
- checkedArr.value= getCheck(data.value,[],auths.data);
- fpDialog.value=true;
- });
- }
- }
-
- //选中的数组遍历
- let getCheck=(item:any,arr:any,auths:any)=>{
- item.forEach(x => {
- if(x.isType=='2' && auths.indexOf(x.auth)!==-1){
- console.log(x.auth,'------',auths)
- //如果是按钮 并且选中了 那么设置树展示
- arr.push(x.id)
- }
- if(x.children && x.children.length>0){
- //如果有子集那么递归子集
- getCheck(x.children,arr,auths)
- }
- });
- return arr;
- }
-
- //分配权限方法
- let fpAuth= async()=>{
- //拿到当前选中的节点的id数组
- let menuIds=tree.value.getCheckedKeys();
- //为角色分配权限
- let res=await setRoleAuth({
- roleId:authRoleId.value,
- menuIds:menuIds
- });
- if(res.code=='200'){
- authRoleId.value='';
- ElMessage.success('分配成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- //关闭窗口
- fpDialog.value = false;
-
-
- }
-
- //--------------------------按钮显示隐藏----------------------------
- //按钮权限
- //添加按钮默认不显示
- let roleErAdd=ref(false);
- //分配权限按钮默认不显示
- let roleErFp=ref(false);
- //修改按钮默认不显示
- let roleErEdit=ref(false);
- //删除按钮默认不显示
- let roleErDel=ref(false);
-
- let getAuthData= async()=>{
- //获取菜单权限
- let res=await getMyAuth();
- //如果存在对应的权限 才显示按钮
- if(res.data.indexOf('role:er:add')!==-1){
- roleErAdd.value=true;
- }
- if(res.data.indexOf('role:er:del')!==-1){
- roleErDel.value=true;
- }
- if(res.data.indexOf('role:er:edit')!==-1){
- roleErEdit.value=true;
- }
- if(res.data.indexOf('role:er:fp')!==-1){
- roleErFp.value=true;
- }
-
- }
-
-
- </script>
-
- <style scoped>
-
- </style>
-
- <style>
-
- </style>
- <template>
- <!--菜单-->
- <el-menu v-for="x in menuList" :key="x.path">
- <!--根据权限 是否展示一级菜单-->
- <el-sub-menu :index="x.path" v-if="!x.meta.hidden">
- <!--插槽占位 显示一级菜单-->
- <template #title>
- <!--显示图标-->
- <el-icon>
- <component :is="x.meta.icon"></component>
- </el-icon>
- <span>{{x.meta.title}}</span>
- </template>
- <!--显示二级菜单-->
- <template v-for="y in x.children" :key="y.path" >
- <!--根据权限 是否展示二级菜单-->
- <el-menu-item :index="y.path" @click="goRouter" v-if="!y.meta.hidden">
- <!--显示图标-->
- <el-icon>
- <component :is="y.meta.icon"></component>
- </el-icon>
- <!--显示标题-->
- {{y.meta.title}}
- </el-menu-item>
- </template>
- </el-sub-menu>
-
- </el-menu>
- </template>
-
- <script setup lang="ts">
- //引入路由器
- import {useRouter} from 'vue-router'
-
- //接收父组件传过来的菜单数组
- defineProps(['menuList'])
-
- //获取路由器对象
- let router=useRouter();
-
- //点击菜单触发的方法
- let goRouter=(vc:any)=>{
- //通过路由器跳转界面
- router.push(vc.index)
- }
-
-
- </script>
-
- <style>
-
- </style>
- <template>
- <div>
- <el-card class="box-card">
- <template #header>
- <div class="card-header">
- <span>用户管理</span>
- </div>
- </template>
-
- <!--有权限才显示-->
- <el-button type="primary" icon="Plus" @click="add" v-if="userErAdd">添加</el-button>
-
-
- <el-table :data="tableData" style="width: 100%" >
- <el-table-column label="序号" width="180" type="index"/>
- <el-table-column prop="account" label="账号" width="180" />
- <el-table-column prop="name" label="姓名" width="180" />
- <el-table-column prop="createTime" label="创建时间" width="200" />
-
- <el-table-column prop="caozuo" label="操作">
- <!--具名插槽-->
- <template #default="caozuo">
- <!--把表格的主键传递过去-->
- <el-button type="primary" icon="Setting" @click="fenPeiRole(caozuo.row.id)" v-if="userErFp">分配角色</el-button>
- </template>
- </el-table-column>
- </el-table>
-
-
- </el-card>
-
-
- <!--点击新增按钮弹出对话框-->
- <el-dialog
- v-model="dialogVisible"
- title="添加"
- width="30%"
- :before-close="handleClose"
- >
- <el-form :model="addBean">
- <el-form-item label="账号" >
- <el-input label-width="80%" v-model="addBean.account"/>
- </el-form-item>
- <el-form-item label="姓名" >
- <el-input label-width="80%" v-model="addBean.name"/>
- </el-form-item>
- <el-form-item label="密码" >
- <el-input label-width="80%" v-model="addBean.password"/>
- </el-form-item>
- </el-form>
-
- <!--底部插槽-->
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="dialogVisible = false">取消</el-button>
- <el-button type="primary" @click="insert">确定</el-button>
- </span>
- </template>
- </el-dialog>
-
- <!--弹出分配角色对话框-->
- <el-dialog
- v-model="dialogRole"
- title="分配角色"
- width="30%"
- :before-close="handleClose"
- >
- <el-form :model="setBean">
- <el-form-item label="用户id">
- <el-input label-width="80%" v-model="setBean.userId" disabled/>
- </el-form-item>
-
- <el-form-item label="角色" >
- <el-select
- v-model="roleIds"
- multiple
- clearable
- collapse-tags
- placeholder=""
- popper-class="custom-header"
- :max-collapse-tags="1"
-
- >
- <template #header>
- <el-checkbox
- v-model="checkAll"
- :indeterminate="indeterminate"
- @change="handleCheckAll"
- >
- All
- </el-checkbox>
- </template>
- <el-option
- v-for="item in cities"
- :key="item.id"
- :label="item.roleName"
- :value="item.id"
- />
- </el-select>
-
- </el-form-item>
-
- </el-form>
-
- <!--底部插槽-->
- <template #footer>
- <span class="dialog-footer">
- <el-button @click="dialogRole = false">取消</el-button>
- <el-button type="primary" @click="updateRole">确定</el-button>
- </span>
- </template>
- </el-dialog>
-
-
- </div>
- </template>
-
- <script setup lang="ts">
- import {ref,onMounted,reactive,watch} from 'vue'
- //引入后端接口
- import {getUserList,addUser,getRoleList,setUserRole,getUserRoleIds,getMyAuth} from '@/api/index'
- import type { CheckboxValueType } from 'element-plus'
- //引入提示
- import { ElMessage } from 'element-plus'
-
-
-
-
-
- //表格数据
- let tableData=ref([]);
-
- //获取分页数据
- let getData=async ()=>{
- //必须异步阻塞去获取 否则拿到的就是一个Promise对象
- let res=await getUserList();
- tableData.value=res.data;
- }
-
- //--------------------------按钮显示隐藏----------------------------
- //添加按钮默认不显示
- let userErFp=ref(false);
- //分配角色按钮默认不显示
- let userErAdd=ref(false);
-
- let getAuthData= async()=>{
- //获取菜单权限
- let res=await getMyAuth();
- //如果存在对应的权限 才显示按钮
- if(res.data.indexOf('user:er:add')!==-1){
- userErAdd.value=true;
- }
- if(res.data.indexOf('user:er:fp')!==-1){
- userErFp.value=true;
- }
-
- }
-
- //加载时调用
- onMounted(()=>{
- //调用查询
- getData();
- //调用权限
- getAuthData();
-
- })
-
-
- //添加对象
- let addBean=reactive({
- name:'',
- account:'',
- password:''
- })
- //默认不显示对话框
- let dialogVisible=ref(false)
- //添加显示对话框
- let add=()=>{
- //显示对话框
- dialogVisible.value=true;
-
- //把输入框显示的内容清空
- addBean.name='';
- addBean.account='';
- addBean.password='';
- }
-
- //添加用户 调用后端接口
- let insert= async ()=>{
- //调用后端添加品牌方法
- let res=await addUser(addBean);
- console.log(res);
- if(res.code=='200'){
- //执行成功后关闭对话框
- dialogVisible.value=false;
- ElMessage.success('添加成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- }
-
- //角色信息
- const cities = ref([])
- //全选
- const checkAll = ref(false)
- //监听值的变化
- const indeterminate = ref(false)
- //角色id 集合
- const roleIds = ref<CheckboxValueType[]>([])
- //分配角色对象
- let setBean=reactive({
- userId:'',
- roleIds:[]
- })
- //默认不显示分配角色对话框
- let dialogRole=ref(false)
- //显示分配角色对话框
- let fenPeiRole= async(id)=>{
- //显示对话框
- dialogRole.value=true;
- //获取后台角色列表接口
- let res=await getRoleList();
- cities.value=res.data;
- //赋值用户id
- setBean.userId=id;
- //获取已经分配过的角色id
- let response=await getUserRoleIds({
- userId:id
- });
- //把已分配过的角色id数组,给roleIds赋值 使得下拉框默认选中
- roleIds.value=response.data;
- }
-
-
-
- // //添加用户 调用后端接口
- let updateRole= async ()=>{
- //把角色id集合赋值 给后台对象
- setBean.roleIds=roleIds.value;
- //调用后端分配角色方法
- let res=await setUserRole(setBean);
- console.log(res);
- if(res.code=='200'){
- //执行成功后关闭对话框
- dialogRole.value=false;
- ElMessage.success('分配成功')
- //调用查询刷新界面
- getData();
- }else{
- //弹窗错误消息
- ElMessage.error(res.msg);
- }
- }
-
- //监听下拉框发生的变化
- watch(roleIds, (val) => {
-
- if (val.length === 0) {
- checkAll.value = false
- indeterminate.value = false
- } else if (val.length === cities.value.length) {
- checkAll.value = true
- indeterminate.value = false
- } else {
- indeterminate.value = true
- }
- })
-
- //点击All 方法
- const handleCheckAll = (val: CheckboxValueType) => {
- indeterminate.value = false
- if (val) {
- roleIds.value = cities.value.map((_) => _.id)
- } else {
- roleIds.value = []
- }
- }
-
- </script>
-
- <style lang="scss">
- .custom-header {
- .el-checkbox {
- display: flex;
- height: unset;
- }
- }
- </style>
npm run dev
用户关联角色
角色分配权限
界面上的菜单和按钮 都会动态显示或者隐藏
如果按钮都没有选择 那么这个二级菜单 不会显示
如果按钮选择一个 那么二级菜单也能访问
退出登录后 会清空token和用户信息
没有token 自动跳转到登录界面
访问错误的路径会显示404
没有路径的权限 访问会进入无权限的界面
注册用户之后 密码都是加密的
在登录的时候 会把密码加密进行对比
用户名:zhangsan
密码:123456
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。