Vue3做出B站【bilibili】 Vue3+TypeScript+ant-design-vue【快速入门一篇文章精通系列(一)前端项目案例】
创始人
2024-05-31 04:34:53
0

本项目分为二部分
1、后台管理系统(用户管理,角色管理,视频管理等)
2、客户端(登录注册、发布视频)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Vue3做出B站【bilibili】 Vue3+TypeScript+ant-design-vue【快速入门一篇文章精通系列(一)前端项目案例】

  • 一、前言
  • 二、项目创建基本页面搭建
    • (一)创建Vue3 + TypeScript项目
      • 1、新建Vue3 项目
      • 2、用WebStorm打开项目
        • 1)打开项目以后执行 `npm install`
        • 2)安装TypeScript
        • 3)设置一下WebStorm配置
      • 3、配置项目
        • 1)安装依赖
        • 2)路由配置
        • 3)pinia配置
        • 4)vite.config.ts配置
        • 5)按需引入ant-design-vue
        • 6)安装axios
      • 4、设置页面路由
    • (二)实现登录页面
      • 1、设置登陆页面
      • 2、设置登录请求
      • 3、创建mock.ts
      • 4、显示验证码
      • 5、在store当中的store.ts设置SET_TOKEN
      • 6、实现登录请求相关内容
      • 7、完善登录
        • (1)在main.ts当中引入antd的全局样式
        • (2)完善request.ts当中响应的内容
  • 三、后台管理界面开发
    • (一)创建index页面
      • 1、新建index页面
      • 2、设置路由
      • 3、完善菜单页面内容
      • 4、Vue代码抽取
        • (1)抽取菜单
        • (2)index
      • 5、设置子路由
      • 6、编写导航栏路由
        • 1)创建需要路由跳转的页面
        • 2)设置页面路由
    • (二)用户登录信息展示
      • 1、完善用户接口
      • 2、设置mock.js
      • 3、设置个人中心的路由
      • 4、设置退出登录
    • (三)动态菜单开发
      • 1、修改一下路由规则
      • 2、设置动态菜单的数据
        • (1)自定义Icon组件
        • (2)SideMenu.vue菜单页面
        • (3)创建保存菜单的状态信息的内容
        • (4)设置mockjs
        • (5)完善SideMenu.vue菜单页面,设置请求并渲染菜单
      • 3、设置动态路由加载一次以后无需二次加载
      • 4、实现动态导航
      • 5、设置侧栏和页面进行动态绑定
      • 6、完善Tabs标签页
    • (四)菜单管理界面开发
      • 1、在Menu当中设置表格样式
      • 2、在Menu当中设置新增和编辑
    • (五)角色管理
      • 1、设置角色信息的增删改查-权限分配
    • (六)用户管理

一、前言

在前端方面我们使用的技术栈包括

TypeScript
Vue3
ant Design Vue
axios
echarts
highcharts
mockjs
pinia
vue-router

二、项目创建基本页面搭建

(一)创建Vue3 + TypeScript项目

1、新建Vue3 项目

npm create vite@latest bilibili-vue3-ts -- --template vue

在这里插入图片描述
将生成的js文件都修改为ts文件
在这里插入图片描述
在这里插入图片描述

2、用WebStorm打开项目

1)打开项目以后执行 npm install

在这里插入图片描述
执行成功
在这里插入图片描述

2)安装TypeScript

安装TypeScript

npm install -g typescript

在这里插入图片描述
安装完成后,在控制台运行如下命令,检查安装是否成功(3.x):

tsc -v

在这里插入图片描述

3)设置一下WebStorm配置

在这里插入图片描述
设置自动编译
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

$FileNameWithoutExtension$.js:$FileNameWithoutExtension$.js.map
$FileDir$

3、配置项目

1)安装依赖

作为前端项目我们使用一些场景的依赖
这里我们只需要将以下依赖复制到package.json,重新运行npm install
将package-lock.json文件夹删除
在这里插入图片描述
在package.json当中
在这里插入图片描述

"dependencies": {"ant-design-vue": "^3.3.0-beta.4","axios": "^0.27.2","echarts": "^5.3.3","echarts-gl": "^2.0.9","highcharts": "^10.2.1","pinia": "^2.0.23","pinia-plugin-persist": "^1.0.0","sass": "^1.54.9","swiper": "^8.4.5","vue": "^3.2.37","vue-router": "^4.1.5","vue3-audio-player": "^1.0.5","vue3-seamless-scroll": "^2.0.1"},"devDependencies": {"less": "^4.1.3","unplugin-auto-import": "^0.11.2","unplugin-vue-components": "^0.22.4","@vitejs/plugin-vue": "^4.0.0","vite": "^4.0.0"}

执行npm install

除了以上安装方式以外,
你也可以自己找到对应依赖的官方网站,
一个一个手动安装

2)路由配置

创建router文件夹
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import { createRouter,createWebHashHistory } from 'vue-router';
import Home from "../views/Home.vue";
import About from "../views/About.vue";
//2、定义一些路由
//每个路由都需要映射到一个组件
//我们后面再讨论嵌套路由
const routes = [{path:"/",component:Home,name:"Home"},{path:"/About",component:About,name:"About"},
];
//3、创建路由实例并传递‘routes’配置
//你可以在这里输入更多的配置,但是我们在这里
const router = createRouter({//4、内部提供了 history 模式的实现。为了简单起见,我们在这里使用hash模式history:createWebHashHistory(),routes, //routes:routes 的缩写
})
export default router

创建Home.vue和About.vue
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述
修改App.vue
在这里插入图片描述



3)pinia配置

在这里插入图片描述
在这里插入图片描述

import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)
export default store

在这里插入图片描述
在这里插入图片描述

import { defineStore } from 'pinia'
export const userStore = defineStore({id: 'user',state: () => {return {title: '',token:''}},getters: {getTitle: (state) => state.title,},actions: {setTitle(title:string) {this.title= title}},// 开启数据缓存// @ts-ignorepersist: { //数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 keyenabled: true}
})

在main.ts当中引入如上内容
在这里插入图片描述

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router/index'
import store  from './store/index'
import { createPinia } from 'pinia'
import * as echarts from 'echarts'let app = createApp(App)
app.config.globalProperties.$echarts = echarts
app.use(router)
app.use(store)
app.use(createPinia)
app.mount('#app')

4)vite.config.ts配置

在这里插入图片描述

//vite.config.js
import { defineConfig } from 'vite'
import {resolve} from 'path'
import vue from '@vitejs/plugin-vue'
import Components from "unplugin-vue-components/vite"
import AutoImport from "unplugin-auto-import/vite"
export default defineConfig({plugins: [vue(),AutoImport({}),Components({}),],// ...resolve: {alias: {'@': resolve(__dirname, './src')}},server: {port: 80,host: true,open: true,proxy: {'/api': {target: 'http://api.cpengx.cn/metashop/api',changeOrigin: true,rewrite: (p) => p.replace(/^\/api/, '')},}},// 开启less支持css: {preprocessorOptions: {less: {javascriptEnabled: true}}}
})

运行测试

npm run dev

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5)按需引入ant-design-vue

在这里插入图片描述

//vite.config.js
import { defineConfig } from 'vite'
import {resolve} from 'path'
import vue from '@vitejs/plugin-vue'
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
import Components from "unplugin-vue-components/vite"
import AutoImport from "unplugin-auto-import/vite"
export default defineConfig({plugins: [vue(),AutoImport({resolvers: [AntDesignVueResolver() ],}),Components({resolvers: [AntDesignVueResolver({importStyle: 'less', // 一定要开启这个配置项}),],}),],// ...resolve: {alias: {'@': resolve(__dirname, './src')}},server: {port: 80,host: true,open: true,proxy: {'/api': {target: 'http://api.cpengx.cn/metashop/api',changeOrigin: true,rewrite: (p) => p.replace(/^\/api/, '')},}},// 开启less支持css: {preprocessorOptions: {less: {modifyVars: { // 在这里自定义主题色等样式'primary-color': '#fb7299','link-color': '#fb7299','border-radius-base': '2px',},javascriptEnabled: true,}}}
})

在Home当中放置一个按钮
在这里插入图片描述




重新运行并访问
在这里插入图片描述

6)安装axios

安装axios:一个基于promise的HTTP库,类ajax

npm install axios

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import axios from 'axios'
// @ts-ignore
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: "/bilibili-api",//baseURL: "/",// 超时timeout: 10000
})
export default service

配置请求

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import request from '../utils/request'
/* 有参  */
export const  getXqInfo  = (params:any) => {return request({method: "GET",url: "/grid/openApi/screen/getXqInfo",params,});
};
/* 无参  */
export const getCommunityOverview = ( ) => {return request({method: "GET",url: "/grid/openApi/screen/getCommunityOverview",});
};

4、设置页面路由

删除页面的自动创建好的页面
在这里插入图片描述
在这里插入图片描述
设置路由
在这里插入图片描述

import { createRouter,createWebHashHistory } from 'vue-router';
import Home from "../views/Home.vue";
import Login from "../views/Login.vue";
//2、定义一些路由
//每个路由都需要映射到一个组件
//我们后面再讨论嵌套路由
const routes = [{path:"/",component:Home,name:"Home"},{path:"/login",component:Login,name:"Login"},
];
//3、创建路由实例并传递‘routes’配置
//你可以在这里输入更多的配置,但是我们在这里
const router = createRouter({//4、内部提供了 history 模式的实现。为了简单起见,我们在这里使用hash模式history:createWebHashHistory(),routes, //routes:routes 的缩写
})
export default router

(二)实现登录页面

1、设置登陆页面

我们找到From表单的内容
https://www.antdv.com/components/form-cn
在这里插入图片描述

在这里插入图片描述

复制上述代码,但是我们并不会直接使用期内容

在这里插入图片描述



访问页面http://localhost/#/login
在这里插入图片描述
删除style.css当中样式
在这里插入图片描述
在这里插入图片描述
调整一下页面
在这里插入图片描述


在这里插入图片描述

2、设置登录请求

在这里插入图片描述

import request from '@/utils/request'
/* 无参  */
export const getCaptchaImg = ( ) => {return request({method: "GET",url: "/captcha",});
};

3、创建mock.ts

安装qs
qs:查询参数序列化和解析库

npm install qs

安装mockjs
mockjs:为我们生成随机数据的工具库

npm install mockjs

在这里插入图片描述
在main.ts当中引入mock.ts
在这里插入图片描述

import "@/mock"

完善mock.ts
在这里插入图片描述

// @ts-ignore
import Mock from "mockjs";const Random = Mock.Randomlet Result = {code: 200,msg: '操作成功',data: null
}Mock.mock('/bilibili-api/captcha','get',()=>{// @ts-ignoreResult.data = {token: Random.string(32),captchaImg:Random.dataImage('120x40','p7n5w')}return Result;
})

4、显示验证码

完善request.ts,设置发起请求的内容
在这里插入图片描述

import axios from 'axios'
// @ts-ignore
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: "/bilibili-api",//baseURL: "/",// 超时timeout: 10000
})
export default service

完善vite.config.ts,设置发起请求的路径和地址
在这里插入图片描述

proxy: {'/bilibili-api': {target: 'http://localhost:8081',changeOrigin: true,rewrite: (p) => p.replace(/^\/bilibili-api/, '')},
}

完善src/api/index.ts设置请求
在这里插入图片描述

import request from '@/utils/request'
/*无参*/
export const getCaptchaImg = () => {return request({method: "GET",url: "/captcha",});
};

设置登录页面完善请求内容
在这里插入图片描述

 

在这里插入图片描述
在这里插入图片描述

import {getCaptchaImg} from "@/api";
const getCaptcha = () => {getCaptchaImg().then(res => {formState.token = res.data.data.token;captchaImg.value = res.data.data.captchaImg;})
}
onMounted(()=>{getCaptcha();
})

访问http://localhost/#/login
在这里插入图片描述

5、在store当中的store.ts设置SET_TOKEN

在这里插入图片描述

SET_TOKEN(token:string ){this.token = tokenlocalStorage.setItem("token",token)},

6、实现登录请求相关内容

在这里插入图片描述

export const userLogin = (data:any) => {return request({url: '/login',method: 'post',data: data})
};

在这里插入图片描述

const router = useRouter();
import { useRouter } from "vue-router";
const user = userStore()const router = useRouter();
const onFinish = (values: any) => {userLogin(formState).then(res => {const jwt = res.headers['authorization']user.SET_TOKEN(jwt);router.push("/");})
};

完善mock.ts
在这里插入图片描述

Mock.mock('/bilibili-api/login','post',()=>{Result.code = 404Result.msg = "验证码错误"return Result;
})

7、完善登录

(1)在main.ts当中引入antd的全局样式

在这里插入图片描述

import 'ant-design-vue/dist/antd.css';

(2)完善request.ts当中响应的内容

在这里插入图片描述

import axios from 'axios'
import {  message as Message, notification } from 'ant-design-vue';
import { useRouter } from "vue-router";
// @ts-ignore
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: "/bilibili-api",// 超时timeout: 10000
})
service.interceptors.request.use(config => {// @ts-ignoreconfig.headers['Authorization'] = localStorage.getItem("token")return config;
});
service.interceptors.response.use(response => {let res = response.dataif (res.code === 200) {return response} else {Message.error(!res.msg ? '系统异常' : res.msg)return Promise.reject(response.data.msg)}}, error => {if (error.response.data) {error.message = error.response.data.msg}if (error.response.status === 401) {useRouter().push("/login")}Message.error(error.message)return Promise.reject(error)}
)
export default service

运行测试
http://localhost/#/login
在这里插入图片描述

三、后台管理界面开发

(一)创建index页面

一般来说,管理系统的页面我们都是头部是一个简单的信息展示系统名称和登录用户信息,然后中间的左边是菜单导航栏,右边是内容,对应到ant Design Vue的组件中,我们可以找到这个Layout 布局容器用于布局,方便快速搭建页面的基本结构。

而我们采用这个布局:
在这里插入图片描述

1、新建index页面

在这里插入图片描述
在这里插入图片描述




2、设置路由

在这里插入图片描述

router.push("/index");

在这里插入图片描述
设置一下状态码使其跳转成功
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、完善菜单页面内容

在这里插入图片描述



在这里插入图片描述

4、Vue代码抽取

(1)抽取菜单

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



在这里插入图片描述
在这里插入图片描述


import SideMenu from "./inc/SideMenu.vue"

在这里插入图片描述

(2)index

将index.vue的内容全部抽取到Home
在这里插入图片描述



5、设置子路由

在这里插入图片描述

		children:[{path:'/index',name:'Index',component:Index}]

在Home.vue当中设置路由
在这里插入图片描述

 

访问页面:http://localhost/#/index
在这里插入图片描述

6、编写导航栏路由

1)创建需要路由跳转的页面

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

防止手残贴上全部代码

import  { createRouter,createWebHashHistory } from 'vue-router';
import Home from "../views/Home.vue";
import Index from "../views/Index.vue";
import Login from "../views/Login.vue";
import Menu from '../views/sys/Menu.vue'
import Role from '../views/sys/Role.vue'
import User from '../views/sys/User.vue'
//2、定义一些路由
//每个路由都需要映射到一个组件
//我们后面再讨论嵌套路由
const routes = [{path:"/",component:Home,name:"Home",children:[{path:'',name:'Index',component:Index},{path:'/index',name:'Index',component:Index},{path:'/users',name:'SysUser',component:User},{path:'/roles',name:'SysRole',component:Role},{path:'/menus',name:'SysMenu',component:Menu}]},{path:"/login",component:Login,name:"Login"},
];
//3、创建路由实例并传递‘routes’配置
//你可以在这里输入更多的配置,但是我们在这里
const router = createRouter({//4、内部提供了 history 模式的实现。为了简单起见,我们在这里使用hash模式history:createWebHashHistory(),routes, //routes:routes 的缩写
})
export default router

访问:http://localhost/#/roles
在这里插入图片描述

访问: http://localhost/#/users
在这里插入图片描述
访问:http://localhost/#/menus

2)设置页面路由

在这里插入图片描述

	主页用户管理角色管理菜单管理数字字典

点击测试
在这里插入图片描述
在这里插入图片描述

(二)用户登录信息展示

管理界面的右上角的用户信息现在是写死的,
因为我们现在已经登录成功,所以我们可以通过接口去请求获取到当前的用户信息了,
这样我们就可以动态显示用户的信息,这个接口比较简单,然后退出登录的链接也一起完成,
就请求接口同时把浏览器中的缓存删除就退出了哈。

1、完善用户接口

在这里插入图片描述

export const getUserInfo = () => {return request({url: '/sys/userInfo',method: 'get',})
};

2、设置mock.js

在这里插入图片描述


Mock.mock('/bilibili-api/sys/userInfo','get',()=>{// @ts-ignoreResult.data = {id:"1",username:"itbluebox",avatar:"https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"}return Result
})

3、设置个人中心的路由

在这里插入图片描述

个人中心

在这里插入图片描述

import UserCenter from '../views/UserCenter.vue'
{path:'/userCenter',name:'UserCenter',component:UserCenter
},

创建对应的页面
在这里插入图片描述
在这里插入图片描述



在这里插入图片描述
在这里插入图片描述

4、设置退出登录

在这里插入图片描述

export const logout = () => {return request({url: '/logout',method: 'get',})
};

在这里插入图片描述

退出

在这里插入图片描述

import { userStore} from '@/store/store'
const user = userStore()
const logOut = () => {logout().then(response => {user.resetState()localStorage.clear();sessionStorage.clear();router.push("/login");});
}

设置Store的状态
在这里插入图片描述

 resetState(){this.token = ""},

设置mock
在这里插入图片描述

Mock.mock('/bilibili-api/logout','get',()=>{return Result;
})

(三)动态菜单开发

1、修改一下路由规则

在这里插入图片描述

{path:'/sys/users',name:'SysUser',component:User},{path:'/sys/roles',name:'SysRole',component:Role},{path:'/sys/menus',name:'SysMenu',component:Menu}

2、设置动态菜单的数据

(1)自定义Icon组件

在这里插入图片描述
目前先这样。后期会对其进行优化
在这里插入图片描述

(2)SideMenu.vue菜单页面

在这里插入图片描述

在这里插入图片描述



刷新并访问页面
在这里插入图片描述

(3)创建保存菜单的状态信息的内容

在这里插入图片描述

menuList:[],authoritys:[]setMenuList(menuList:any) {this.menuList = menuList},setAuthoritys(authoritys:any) {this.authoritys = authoritys},

发送获取菜单的请求
在这里插入图片描述

export const nav = () => {return request({url: '/sys/menu/nav',method: 'get',})
};

在路由当中获取拿到menuList,
在这里插入图片描述

import {nav} from "@/api";
import { userStore} from '@/store/store'

设置在路由加载前拿到前,拿到菜单的内容并添加到Store
在这里插入图片描述

router.beforeEach((to,from,next)=>{nav().then(res => {//拿到menuListuserStore().setMenuList(res.data.data.nav)userStore().setAuthoritys(res.data.data.authoritys)})next()
})

(4)设置mockjs

在这里插入图片描述


Mock.mock('/bilibili-api/sys/menu/nav', 'get', () => {let nav = [{key:101,title: '系统管理',name: 'SysMange',icon: 'setting-outlined',path: '',children: [{key:102,title: '用户管理',name: 'SysUser',icon: 'user-outlined',path: '/sys/users',children: []},{key:103,title: '角色管理',name: 'SysUser',icon: 'user-group-add-outlined',path: '/sys/roles',children: []},{key:104,title: '菜单管理',name: 'SysMenu',icon: 'menu-outlined',path: '/sys/menus',children: []}]},{key:201,title: '系统工具',name: 'SysTools',icon: 'menu-outlined',path: '',children: [{title: '数字字典',name: 'SysDict',icon: 'container-outlined',path: '/sys/dicts',children: []}]}];// @ts-ignorelet authoritys = [];// @ts-ignoreResult.data = {nav: nav,// @ts-ignoreauthoritys: authoritys}return Result;
})

(5)完善SideMenu.vue菜单页面,设置请求并渲染菜单

在这里插入图片描述

import {ref,reactive,onMounted} from "vue";
import {AppstoreOutlined,MailOutlined,SettingOutlined,TeamOutlined,UserOutlined,MenuOutlined,ContainerOutlined
} from '@ant-design/icons-vue';
import Icon from "@/components/Icon.vue"
import { userStore} from '@/store/store'
let selectedKeys =ref(['1'])
let selectedKeysTop =ref(['1'])
let collapsed =ref(false)
let menuList = reactive({menus:  []
})
onMounted(()=>{menuList.menus = userStore().getMenuList
})

在这里插入图片描述

3、设置动态路由加载一次以后无需二次加载

在这里插入图片描述

hasRoutes:falsegetHasRoutes: (state) => state.hasRoutes,changeRouteStatus(hasRoutes:any){this.hasRoutes = hasRoutes;
}

在这里插入图片描述

router.beforeEach((to,from,next)=>{let hasRoutes = userStore().getHasRoutes;if(!hasRoutes){nav().then(res => {//拿到menuListuserStore().setMenuList(res.data.data.nav)userStore().setAuthoritys(res.data.data.authoritys)hasRoutes = trueuserStore().changeRouteStatus(hasRoutes)})}next()
})

4、实现动态导航

在这里插入图片描述
在这里插入图片描述



查看效果
在Home当中引入该内容
在这里插入图片描述

import Tabs from "@/views/inc/Tabs.vue"

在这里插入图片描述

5、设置侧栏和页面进行动态绑定

  • 在store.ts当中设置添加tab 的功能
    在这里插入图片描述
			 editableTabsValue: 0,editableTabs: [{title: '首页',content: '/index',key: 0,closable: false,}],getEditableTabsValue: (state) => state.editableTabsValue,getEditableTabs: (state) => state.editableTabs,

在这里插入图片描述

addTab(tab:any) {this.editableTabs.push({title: tab.title,content: tab.path,key: tab.key,closable: true,});},setEditableTabs(tab:any){this.editableTabs = tab;},setEditableTabsIndex0(){this.editableTabsValue = 0;},setEditableTabsIndexClearALL(){this.editableTabs  = [{title: '首页',content: '/index',key: 0,closable: false,}]},setEditableTabsValue(tabValue:number){this.editableTabsValue = tabValue;}

在这里插入图片描述

 主页
{{item.title}}

在这里插入图片描述

onMounted(()=>{var menus = userStore().getEditableTabsValue;//设置高亮同步selectedKeys.value.length = 0;selectedKeys.value.push(menus+"")menuList.menus = userStore().getMenuList;
});
const selectMenu = (item:any) => {userStore().addTab(item)
}
const selectMenuIndex0 = () => {userStore().setEditableTabsIndex0()
}

6、完善Tabs标签页

在这里插入图片描述


  • 我们发现重复点击会重复的添加到上面,现在设置重复点击不会出现重复的信息
    在这里插入图片描述
    在这里插入图片描述
		addTab(tab:any) {let index = this.editableTabs.findIndex(e => e.title === tab.title )if(index === -1){this.editableTabs.push({title: tab.title,content: tab.path,key: tab.key,closable: true,});}this.editableTabsValue = tab.key;},

多次点击以后不会出现
在这里插入图片描述

  • 设置点击tab进行内容的切换
    在这里插入图片描述


在这里插入图片描述

const onTabClick = (targetKey: string) => {let jsonArray = userStore().getEditableTabslet path = "";for(let i =0;i < jsonArray.length;i++){if(targetKey == jsonArray[i].key){path = jsonArray[i].content;}}userStore().setEditableTabsValue(targetKey)router.push(path);
}

在这里插入图片描述

 
{{editableTabsValue}}
后台管理系统

在这里插入图片描述

let editableTabsValue = computed({get(){let key = userStore().getEditableTabsValue;selectedKeys.value.length = 0;selectedKeys.value.push(key)return key;},set(val:any){userStore().setMenuList(val);}
});

在这里插入图片描述
完善清除功能
在这里插入图片描述
在这里插入图片描述

const removeAll = () => {activeKey.value = `newTab${++newTabIndex.value}`;userStore().setEditableTabsIndexClearALL()userStore().setEditableTabsValue("1")router.push("/index");
};

设置通过ip路径访问的时候,设置对应tabs和menu

在这里插入图片描述



访问:http://localhost/#/sys/menus

在这里插入图片描述
设置退出登录后清除tab
在这里插入图片描述

 退出

在这里插入图片描述

const logOut = () => {logout().then(response => {user.resetState()user.setEditableTabsIndexClearALL()user.setEditableTabsIndex0()localStorage.clear();sessionStorage.clear();router.push("/login");});
}

(四)菜单管理界面开发

1、在Menu当中设置表格样式

在这里插入图片描述

在这里插入图片描述

上面当面数据超出页面的时候页面跟着滚动这样不太好我们优化一下,设置侧边栏和头部不懂,设置内容区域滚动
在这里插入图片描述
在这里插入图片描述



内容滚动头部底部不滚
在这里插入图片描述

2、在Menu当中设置新增和编辑

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

(五)角色管理

1、设置角色信息的增删改查-权限分配

在这里插入图片描述


在这里插入图片描述

(六)用户管理

用户的增删改查以及对应的权限
在这里插入图片描述

相关内容

热门资讯

122.(leaflet篇)l... 听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
Vue使用pdf-lib为文件... 之前也写过两篇预览pdf的,但是没有加水印,这是链接:Vu...
PyQt5数据库开发1 4.1... 文章目录 前言 步骤/方法 1 使用windows身份登录 2 启用混合登录模式 3 允许远程连接服...
Android studio ... 解决 Android studio 出现“The emulator process for AVD ...
Linux基础命令大全(上) ♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维...
再谈解决“因为文件包含病毒或潜... 前面出了一篇博文专门来解决“因为文件包含病毒或潜在的垃圾软件”的问题,其中第二种方法有...
南京邮电大学通达学院2023c... 题目展示 一.问题描述 实验题目1 定义一个学生类,其中包括如下内容: (1)私有数据成员 ①年龄 ...
PageObject 六大原则 PageObject六大原则: 1.封装服务的方法 2.不要暴露页面的细节 3.通过r...
【Linux网络编程】01:S... Socket多进程 OVERVIEWSocket多进程1.Server2.Client3.bug&...
数据结构刷题(二十五):122... 1.122. 买卖股票的最佳时机 II思路:贪心。把利润分解为每天为单位的维度,然后收...
浏览器事件循环 事件循环 浏览器的进程模型 何为进程? 程序运行需要有它自己专属的内存空间࿰...
8个免费图片/照片压缩工具帮您... 继续查看一些最好的图像压缩工具,以提升用户体验和存储空间以及网站使用支持。 无数图像压...
计算机二级Python备考(2... 目录  一、选择题 1.在Python语言中: 2.知识点 二、基本操作题 1. j...
端电压 相电压 线电压 记得刚接触矢量控制的时候,拿到板子,就赶紧去测各种波形,结...
如何使用Python检测和识别... 车牌检测与识别技术用途广泛,可以用于道路系统、无票停车场、车辆门禁等。这项技术结合了计...
带环链表详解 目录 一、什么是环形链表 二、判断是否为环形链表 2.1 具体题目 2.2 具体思路 2.3 思路的...
【C语言进阶:刨根究底字符串函... 本节重点内容: 深入理解strcpy函数的使用学会strcpy函数的模拟实现⚡strc...
Django web开发(一)... 文章目录前端开发1.快速开发网站2.标签2.1 编码2.2 title2.3 标题2.4 div和s...