???|??? V3-Admin 开源啦
? 简介
v3-admin 是一个中后台管理系统基础解决方案,基于 Vue3、TypeScript、Element-Plus 和 Vue-Cli 4.51?? 功能
- 用户管理
- 登录
- 注销- 权限验证
- 页面权限
- 指令权限- 多环境
- development
- test
- production- 全局功能
- svg
- 国际化
- 多主题切换(内置黑暗主题)
- 动态侧边栏
- 动态面包屑
- 标签页快捷导航
- Screenfull 全屏
- 自适应收缩侧边栏- 错误页面
- 401
- 404- Dashboard
- admin
- editor- 自动部署
2?? 目录
# v3-admin
├─ .env.development# 开发环境
├─ .env.production# 生产环境
├─ .env.test# 测试环境
├─ .eslintrc.js# eslint
├─ deploy# 自动部署
├─ public
│├─ favicon.ico
│├─ index.html
├─ src
│├─ @types# ts 声明
│├─ api# api 接口
│├─ assets# 静态资源
│├─ components# 全局组件
│├─ config# 全局配置
│├─ constant# 常量/枚举
│├─ directives# 全局指令
│├─ layout# 布局
│├─ locales# 国际化
│├─ model# 全局 model
│├─ plugins# 插件
│├─ router# 路由
│├─ store# vuex store
│├─ styles# 全局样式
│├─ utils# 全局公共方法
│└─ views# 所有页面
│├─ App.vue# 入口页面
│├─ main.ts# 入口文件
│├─ permission.ts# 权限管理
│└─ shims.d.ts# 模块注入
├─ tsconfig.json# ts 编译配置
└─ vue.config.js# vue-cli 配置
3?? 安装
# 克隆项目
git clone https://github.com/v3-projects/v3-admin# 进入项目目录
cd v3-admin# 安装依赖
yarn# 启动项目
yarn dev
基础 1?? 路由 配置项
// 默认false,设置 true 的时候该路由不会在侧边栏出现
hidden: true// 设置 noRedirect 的时候该路由在面包屑导航中不可被点击
redirect: 'noRedirect'// 设定路由的名字,一定要填写不然重置路由可能会出问题
name: 'router-name'meta: {
// 设置该路由进入的权限,支持多个权限叠加
roles: ['admin', 'editor']
// 设置该路由在侧边栏和面包屑中展示的名字
title: 'title'
// 设置该路由的图标,记得将 svg 导入 @/assets/svg-icons/icons
icon: 'svg-name'
// 默认true,如果设置为false,则不会在面包屑中显示
breadcrumb: false
// 默认false,如果设置为true,它则会固定在 tags-view 中
affix: true// 当一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式
// 只有一个时,会将那个子路由当做根路由显示在侧边栏
// 若想不管路由下面的 children 声明的个数都显示你的根路由
// 可以设置alwaysShow: true,这样就会忽略之前定义的规则,一直显示根路由
alwaysShow: true// 当设置了该属性,进入路由时,则会高亮 activeMenu 属性对应的侧边栏
activeMenu: '/dashboard'
}
动态路由
constantRoutes
把不需要判断权限的路由放置在常驻路由里面,如 /login
、/dashboard
。asyncRoutes
放置需求动态判断权限并通过 addRoute
动态添加的路由。添加动态路由方法:
案例:在
@/router/asyncModules
下面创建例如 permission.ts
文件import { RouteRecordRaw } from 'vue-router'
import Layout from '@/layout/index.vue'const permissionRouter: Array = [
{
path: '/permission',
component: Layout,
name: 'Permission',
redirect: '/permission/directive',
meta: {
title: 'permission',
icon: 'lock',
roles: ['admin', 'editor'], // 可以在根路由中设置角色
alwaysShow: true // 将始终显示根菜单
},
children: [
{
path: 'page',
component: () => import(/* webpackChunkName: "permission-page" */ '@/views/permission/page.vue'),
name: 'PagePermission',
meta: {
title: 'pagePermission',
roles: ['admin'] // 或者在子导航中设置角色
}
},
{
path: 'directive',
component: () => import(/* webpackChunkName: "permission-directive" */ '@/views/permission/directive.vue'),
name: 'DirectivePermission',
meta: {
title: 'directivePermission' // 如果未设置角色,则表示:该页面不需要权限,但会继承根路由的角色
}
}
]
}
]export default permissionRouter
2?? 侧边栏和面包屑 侧边栏
文章图片
文章图片
侧边栏
@/layout/components/sidebar
是通过读取路由并结合权限判断而动态生成的(换句话说就是常驻路由 + 有权限的路由)侧边栏外链
可以在侧边栏中配置一个外链,只要你在 path 中填写了合法的 url 路径,当你点击侧边栏的时候就会帮你新开这个页面
{
path: 'link',
component: Layout,
children: [
{
path: 'https://github.com/v3-projects/v3-admin',
meta: { title: 'link', icon: 'link' },
name: 'Link'
}
]
}
面包屑
文章图片
面包屑
@/components/bread-crumb
也是根据路由动态生成的,为路由设置 breadcrumb: false
时该路由将不会出现在面包屑中,设置 redirect: 'noRedirect'
时该路由在面包屑中不能被点击3?? 权限 登录时通过获取当前用户的权限(角色)去比对路由表,生成当前用户具有的权限可访问的路由表,通过
addRoute
动态挂载到 router 上角色控制权限
控制代码都在
@/permission.ts
中,这里可根据具体的业务做响应的修改:import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import router from '@/router'
import { RouteLocationNormalized } from 'vue-router'
import { useStore } from './store'
import { UserActionTypes } from './store/modules/user/action-types'
import { PermissionActionType } from './store/modules/permission/action-types'
import { UserMutationTypes } from './store/modules/user/mutation-types'
import { ElMessage } from 'element-plus'
import { whiteList } from './config/white-list'
import rolesSettings from './config/roles'NProgress.configure({ showSpinner: false })router.beforeEach(async(to: RouteLocationNormalized, _: RouteLocationNormalized, next: any) => {
NProgress.start()
const store = useStore()
// 判断该用户是否登录
if (store.state.user.token) {
if (to.path === '/login') {
// 如果登录,并准备进入 login 页面,则重定向到主页
next({ path: '/' })
NProgress.done()
} else {
// 检查用户是否已获得其权限角色
if (store.state.user.roles.length === 0) {
try {
// 注意:角色必须是一个对象数组! 例如: ['admin'] 或 ['developer', 'editor']
await store.dispatch(UserActionTypes.ACTION_GET_USER_INFO, undefined)
if (rolesSettings.openRoles) {
// 获取接口返回的 roles
const roles = store.state.user.roles
// 根据角色生成可访问的 routes
store.dispatch(PermissionActionType.ACTION_SET_ROUTES, roles)
} else {
// 没有开启角色功能,则启用默认角色
store.commit(UserMutationTypes.SET_ROLES, rolesSettings.defaultRoles)
store.dispatch(PermissionActionType.ACTION_SET_ROUTES, rolesSettings.defaultRoles)
}
// 动态地添加可访问的 routes
store.state.permission.dynamicRoutes.forEach((route) => {
router.addRoute(route)
})
// 确保添加路由已完成
// 设置 replace: true, 因此导航将不会留下历史记录
next({ ...to, replace: true })
} catch (err) {
// 删除 token,并重定向到登录页面
store.dispatch(UserActionTypes.ACTION_RESET_TOKEN, undefined)
ElMessage.error(err || 'Has Error')
next('/login')
NProgress.done()
}
} else {
next()
}
}
} else {
// 如果没有 token
if (whiteList.indexOf(to.path) !== -1) {
// 如果在免登录的白名单中,则直接进入
next()
} else {
// 其他没有访问权限的页面将被重定向到登录页面
next('/login')
NProgress.done()
}
}
})router.afterEach(() => {
NProgress.done()
})
取消角色
假如你的业务场景中没有
角色
的概念,那么在 @/config/roles
里可以关闭角色功能,关闭后系统将启用默认角色(一般为最高权限的 admin 角色),即每个登录的用户都可见所有路由interface RolesSettings {
// 是否开启角色功能(开启后需要后端配合,在查询用户详情接口返回当前用户的所属角色)
openRoles: boolean
// 当角色功能关闭时,当前登录用户的默认角色将生效(默认为admin,拥有所有权限)
defaultRoles: Array
}const rolesSettings: RolesSettings = {
openRoles: true,
defaultRoles: ['admin']
}export default rolesSettings
指令权限
简单快速的实现按钮级别的权限判断(已注册到全局,可直接使用):
admin可见
editor可见
admin和editor都可见
但在某些情况下,不适合使用
v-permission
。例如:Element 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。这时候可以使用权限判断函数
import { checkPermission } from '@/utils/permission'
admin可见
editor可见
admin和editor都可见
4?? 发送HTTP请求 大致的流程如下:
graph LR
页面/交互 --> 统一管理的API --> 封装的service.ts --> 服务器
统一管理的 API
import 形式
@/api/login.ts
import { request } from '@/utils/service'interface UserRequestData {
username: string
password: string
}export function accountLogin(data: UserRequestData) {
return request({
url: 'user/login',
method: 'post',
data
})
}
封装的 service.ts
@/utils/service.ts
是基于 axios 的封装,封装了全局 request 拦截器、response 拦截器、统一的错误处理、统一做了超时处理、baseURL设置、CancelToken 等。5?? 多环境 构建
项目开发完成,打包代码时,内置两种环境:
# 打包测试环境
yarn build:test# 打包正式环境
yarn build:prod
变量
在
.env.production
等 .env.xxx
文件中,配置了该环境对应的变量:# 当前运行的环境
NODE_ENV=production
# 当前环境对应接口的 baseURL
VUE_APP_BASE_API = 'https://www.xxx.com'
获取方式:
console.log(process.env.NODE_ENV)
console.log(process.env.VUE_APP_BASE_API)
?? 进阶 1?? ESLint 规范代码很重要!
- 配置项:在
.eslintrc.js
文件中 - 取消自动校验:
@/config/vue.custom.config.ts
中将lintOnSave
设置为false
- 推荐 VSCode 的 ESlint 插件,它可在写代码时,将不符合规范的代码标红,并且在你保存代码是自动修复一些简单的标红的代码(VSCode 配置 ESlint 教程可自行 Google)
- 手动校验:
yarn lint
(提交代码前执行该命令,特别是在你 lintOnSave 为 false 的情况下)
package.json
中配置了 gitHooks,每次 commit 时都将检测代码"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,vue,ts,tsx}": [
"vue-cli-service lint",
"git add"
]
}
3?? 跨域
@/config
文件夹下存放了内置的一些配置项,比如 white-list
路由白名单,vue.custom.config
vue.config 文件配置等。其中的
vue.custom.config
里就有 proxy
进行反向代理。与之对应的生产环境,则可以使用
nginx
来做反向代理。反向代理
const vueDefaultConfig = {
// ...其他配置
devServer: {
// ...其他配置
proxy: {
'/api/': {
target: 'http://xxxxxx/api/',
ws: true,
pathRewrite: {
'^/api/': ''
},
changeOrigin: true,
secure: false
}
}
}
}module.exports = vueDefaultConfig
CORS
这种方案对于前端来说没有什么工作量,和正常发送请求写法上没有任何区别,工作量基本都在后端这里。
实现 CORS 之后,不管是开发环境还是生产环境,都能方便的调用接口。
4?? SVG 全局
@/components/svg-icon
组件,图标存放在 @/assets/svg-icons/icons
使用方式
无需在页面中引入组件,可直接使用
下载 icon
推荐 iconfont
5?? 自动部署 在
deploy/index.js
文件里填写服务器的IP、端口、用户名、密码等信息,再执行 yarn deploy
命令即可自动发布打包好的 dist 文件到对应的服务器注意:该文件中的用户名密码等信息为敏感信息,勿上传到远程仓库,这一点很重要!6?? 新增主题(黑暗主题为例) 新增主题样式文件
src/style/theme/dark/index.scss
src/style/theme/dark/setting.scss
src/style/theme/register.scss
src/config/theme.ts
剩下 1% 可以加群问我,然后我偷偷去 Google
2?? 依赖失败
- 不要使用 cnpm
- 推荐用 yarn
- 尝试删除 node_modules 后再次依赖
- Google 一下
@/config/vue.custom.config.ts
文件中 publicPath
的值从 ./
修改为 /
? 其他 1?? 站在巨人的肩膀上
- vue-element-admin
- vue3-composition-admin
- d2-admin
- vue-vben-admin
推荐阅读
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 拍照一年啦,如果你想了解我,那就请先看看这篇文章
- 结营啦!
- 探索免费开源服务器tomcat的魅力
- 520情人节快乐啦啦啦
- 年末的欢喜
- 寻找天使啦~~~
- 慌慌张张的2020年,再见啦!
- 要玩转这个星际争霸II开源AI,你只需要i5+GTX1050
- 鸡翅膀