vue-admin-better代码解析
前言
本文仅在记录学习vue-admin-better
的代码,仅供学习研究
vue-admin-better
为chuzhixin
开源的免费商用的后台管理前端代码
项目使用方法
使用cmd进入存放 vue-admin-better
的目录下,输入 npm install --legacy-peer-deps
进行安装,然后使用 npm run serve
即可启动
根目录文件
IDE 配置文件
.browserslistrc
.browserslistrc
是在不同的前端工具之间共用目标浏览器和 node 版本的配置文件
# 支持浏览器配置
> 1% # 代表全球超过1%使用的浏览器
last 2 versions # 使用最后两个版本
not dead # 不支持已经停止更新和维护的浏览器。
.editorconfig
.editorconfig
是用于跨不同的编辑器和IDE为多个开发人员维护一致的编码风格的配置文件
# 编辑器配置
root = true # 指定停止在查找.editorconfig文件的父级目录,确保只有项目根目录的.editorconfig生效
[*]
charset = utf-8 # 指定文件的字符集为UTF-8
end_of_line = lf # 指定换行符使用LF(Unix风格)
indent_size = 2 # 设置缩进大小为2个空格
indent_style = space # 使用空格而不是制表符进行缩进
insert_final_newline = true # 在文件末尾插入一个空白行
trim_trailing_whitespace = true # 删除行尾多余的空格
[*.md]
trim_trailing_whitespace = false # 在Markdown文件中,保留行尾的空格
ESLint 配置文件
ESLint为JS插件,用于修复JS中的常见问题
.eslintignore
当 ESLint 运行时,会忽略
.eslintignore
中定义的文件
.eslintrc.js
为ESLint的配置文件
Git 配置文件
团队协作工具
.gitattributes
当有文件创建或更改时,根据
.gitattributes
的配置来设置文件属性
.gitignore
git
提交时忽略的文件
deploy.sh
包含一系列命令和程序的shell文件
用于一键部署项目
push.sh
同上,用于一键推送项目
Stylelint 配置文件
CSS代码检查器,代码审查工具,用于团队合作
.stylelintrc.js
是 Stylelint 的配置文件,用于配置和定义代码风格规则以及代码检查的行为
/* 继承了两个配置文件:
stylelint-config-recess-order: 这是一个 Stylelint 插件,它提供了一些规则来强制 CSS 属性的顺序
stylelint-config-prettier: 这是与 Prettier 配合使用的配置文件,确保 Stylelint 规则不会与 Prettier 冲突
*/
module.exports = {
extends: ['stylelint-config-recess-order', 'stylelint-config-prettier'],}
Babel 配置文件
Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中
babel.config.js
是 Babel 的配置文件,用于配置 Babel 转译器的行为
/* 使用了 @vue/cli-plugin-babel/preset 预设,
这是 Vue CLI 默认的 Babel 预设,包含了一组用于转译 Vue 项目的默认配置。
*/
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
}
Node.js 配置文件
运行Vue必备的环境
package-lock.json
用于描述项目的确切依赖树。它的目的是锁定安装的包的版本,以确保在不同的环境中或不同的时间点,项目的依赖关系都是一致的。
用于记录该项目使用的哪些包,方便他人部署此项目
{
// 项目名称
"name": "vue-admin-better",
// 项目版本号
"version": "2.5.0",
// 文件版本号
"lockfileVersion": 3,
// 表面此文件由npm5或更高版本生成
"requires": true,
// 安装的包文件信息
"packages":{}
}
package.json
用于描述项目的配置文件,包含了项目的元数据和依赖信息
{
// 项目名称
"name": "vue-admin-better",
// 项目版本
"version": "2.5.0",
// 项目作者
"author": "vue-admin-better",
"participants": [],
// 项目的主页
"homepage": "https://chu1204505056.gitee.io/vue-admin-better",
// 包含可以用npm执行的脚本
"scripts": {},
// 项目版本库信息,包括类型和 URL
"repository": {},
// 钩子配置,提交时检查是否有所遗漏,确保测试运行,以及核查代码
"gitHooks": {},
// 配置了在提交前执行的 lint 操作;先执行配置的操作,再添加到暂存区
"lint-staged": {},
// 项目运行时的依赖
"dependencies": {},
// 项目开发时的依赖
"devDependencies": {},
// 关键词,用于描述项目
"keywords": [],
// 指定项目所需的 Node.js 和 npm 版本。
"engines": {}
}
pnpm包管理器
类似于npm的包管理器
pnpm-lock.yaml
使用 pnpm 包管理器时生成的锁定文件,包含了项目的确切依赖关系和版本信息
Prettier 配置文件
Prettier为代码格式化工具,在保存时进行格式化
prettier.config.js
Prettier 工具的配置文件,用于指定代码格式化的规则和选项
module.exports = {
printWidth: 140, // 每行代码的最大宽度为140个字符
tabWidth: 2, // 使用2个空格缩进
useTabs: false, // 不使用制表符进行缩进
semi: false, // 不使用分号作为语句结束符
singleQuote: true, // 使用单引号而不是双引号
quoteProps: 'as-needed', // 只在必要时为对象属性添加引号
jsxSingleQuote: false, // 在 JSX 中不使用单引号
trailingComma: 'es5', // 使用 ES5 的尾随逗号风格
bracketSpacing: true, // 在对象字面量的括号之间保留空格
arrowParens: 'always', // 在单参数箭头函数中始终包含括号
htmlWhitespaceSensitivity: 'ignore', // 在 HTML 文件中忽略空格敏感度
vueIndentScriptAndStyle: true, // 缩进 Vue 文件中的 <script> 和 <style> 标签
endOfLine: 'lf', // 使用 LF(Unix风格)的换行符
}
Vue配置文件
vue.config.js
用于配置 Vue 项目的配置文件,例如修改 webpack 配置、配置代理、调整输出路径等
LICENSE
此项目采用 MIT
许可证,其他任何衍生版本必须保留原作者版权信息;另外开源版本可免费用于商业用途
目录文件
.github
通常用于存放 GitHub 仓库的一些配置文件,用于自动化和规范化项目的一些行为
FUNDING.yml
用于定义项目的财务支持信息
.vscode
VSCode编辑器的项目特定配置,为了在项目中实现一些特定的开发环境和工作流的需求
settings.json
用于定义项目或工作区的编辑器设置;这个文件允许你自定义编辑器的行为
node_modules
Node.js 项目中的一个文件夹,用于存放项目的依赖模块(第三方库或工具)
public
用于存放静态资源
static
存放静态的css
loading.css
带有旋转的四个小圆点的加载动画
favicon_backup.ico
网站的备用图标文件
favicon.ico
网站的图标
index.html
通过设置,用于提高在搜索引擎中的排名;以及不允许使用
http
来访问
robots.txt
该文件用于指导网络爬虫(例如搜索引擎爬虫,如何爬取网站内容的文本文件
vab-icon
方便项目直接使用矢量图标,而无需使用图片文件
lib
存放项目的库文件或库代码
vab-icon.umd.min.js
UMD格式的、经过压缩的JS文件,用于存放图标信息
package.json
描述项目配置信息
layouts
布局组件或模块存放在此目录
Permissions 权限
用于处理用户权限相关内容
permissions.js
自定义permissions模块
export default{
/* VUE中的钩子函数,被绑定元素插入父节点时调用 */
// element为指令所绑定的元素,用来直接操作DOM;
// binding为一个对象,包含绑定的值value
inserted(element, binding) {
/* JS中的解构赋值写法,可以直接从数组或对象中提取数据 */
// 将binding对象中value属性的值赋给value
const { value } = binding
// 获取用户权限信息给permissions
const permissions = store.getters['user/permissions']
/* 判断用户是否有指定的任一权限 */
......
}
}
index.js
用于根据用户的权限来控制 DOM 元素的显示和隐藏
VabColorfullIcon 图标显示
提供一种显示彩色图标的通用方法
index.vue
<template>
<img
// 判断是否为外链
v-if="isExternal"
// 返回外部图标样式
:src="styleExternalIcon"
class="svg-external-icon svg-icon"
// 事件监听器,一键绑定监听器到当前组件
v-on="$listeners"
/>
</template>
VabErrorLog 错误日志
用于处理应用程序中的错误日志
index.vue
<template>
<!-- 当有错误时显示该组件 -->
<div v-if="errorLogs.length > 0">
<!-- 显示错误数量、显示错误详细信息 -->
......
</div>
</template>
<script>
export default{
// 组件名称
name: 'VabErrorLog',
data(){
return{
// 控制错误日志对话框的显示状态
dialogTableVisible: false,
// 应用标题
title: title,
// 应用缩写
abbreviation: abbreviation,
// 搜索列表,包含一组搜索引擎的信息
searchList: [],
}
},
// 从 Vuex store 中获取错误日志信息
computed: {},
methods: {
// 清除所有错误日志,并隐藏对话框
clearAll() {},
// 解码 Unicode 字符串
decodeUnicode(str) {},
},
}
</script>
VabFullScreenBar 全屏组件
控制界面全屏
index.vue
<template>
<!-- 动态的title属性,用于显示鼠标悬停时的提示信息 -->
<span :title="isFullscreen ? '退出全屏' : '进入全屏'">
<!-- 根据是否全屏,显示不同的图标 -->
<vab-icon>......</vab-icon>
</span>
</template>
VabGithubCorner 显示GitHub角标
用于在网页中显示 GitHub 角标(GitHub Corner)
index.vue
用于在网页中显示 GitHub 角标(GitHub Corner)
VabQueryForm 查询表单组件
用于在项目中创建用于搜索和过滤数据的表单
VabQueryFormBottomPanel.vue
表单的底部面板或底部操作区域
<!-- 表单的底部面板或底部操作区域 -->
<template>
<!-- 使用 Element UI 的栅格系统,span表示栅格占据的列数 -->
<el-col :span="24">
<!-- 底部面板的容器 -->
<div class="bottom-panel">
<!-- 使用插槽 允许在组件的使用地方插入其他内容 -->
<slot></slot>
</div>
</el-col>
</template>
<script>
export default {
name: 'VabQueryFormBottomPanel',
// 组件的 props
props: {},
// 组件的数据
data() {
return {}
},
// 组件创建时执行的生命周期钩子
created() {},
// 组件挂载到 DOM 时执行的生命周期钩子
mounted() {},
// 组件的方法
methods: {},
}
</script>
VabQueryFormLeftPanel.vue
在表单页面中创建左侧面板
<template>
<!-- 通过 Element UI 的 el-col 组件实现响应式布局,根据屏幕大小设置列宽度。 -->
<el-col :lg="span" :md="24" :sm="24" :xl="span" :xs="24">
......
</el-col>
</template>
<script>
export default{
props: {
// 控制左侧面板的列宽,默认为 14
span: {
type: Number,
default: 14,
},
},
}
</script>
VabQueryFormRightPanel.vue
表单页面的右侧面板
同:VabQueryFormLeftPanel.vue
VabQueryFormTopPanel.vue
表单的顶部面板部分
同:VabQueryFormBottomPanel.vue
index.vue
<template>
<!-- 使用 Element UI 的 el-row 组件,设置 gutter 为 0,表示没有间隙 -->
<el-row :gutter="0" class="vab-query-form">
<!-- 使用插槽展示父组件传递过来的内容 -->
<slot></slot>
</el-row>
</template>
VabRemixIcon 展示图标
用于集成和展示 Remix 图标库中的图标
index.vue
与
VabColorfullIcon
的内容大致相同
VabSideBar 侧边栏组件
处理侧边栏菜单的逻辑
components
包含了可复用组件
VabMenuItem.vue
侧边栏中的单个菜单项的组件,包含菜单项的名称、图标、点击事件等相关信息
<template>
<!-- el-menu-item 组件,绑定索引值和点击事件 -->
<el-menu-item :index="handlePath(routeChildren.path)" @click="handleLink">
<!-- 菜单项图标 -->
<vab-icon ... />
<!-- 菜单项标题 -->
<span>{{ routeChildren.meta.title }}</span>
<!-- 菜单项标签 -->
<el-tag ... >
{{ routeChildren.meta.badge }}
</el-tag>
</el-menu-item>
</template>
<script>
......
export default{
props: {
// 子路由信息对象
routeChildren: {},
// 菜单项对象
item: {},
// 完整路径字符串
fullPath: {},
},
methods: {
// 处理路径方法
handlePath(routePath) {},
// 处理链接点击事件方法
handleLink() {
...
// 判断链接打开方式为 '_blank',即 新链接 打开
if (target === '_blank') {}
//当前页打开链接 (target 不是 _blank),即当前链接打开
else{}
},
}
</script>
VabSubmenu.vue
表示侧边栏中的子菜单的组件,以创建多层级的侧边栏导航结构
<!-- 表示侧边栏中的子菜单的组件,以创建多层级的侧边栏导航结构 -->
<template>
<!-- 表示一个 Element UI 的子菜单项 -->
<el-submenu
// 用于在组件中引用子菜单
ref="subMenu"
// 建立唯一索引
:index="handlePath(item.path)"
// 表示子菜单不追加到body元素上
:popper-append-to-body="false"
>
<!-- 子菜单标题部分,包括图标组件的渲染 -->
<template slot="title">
</template>
<!-- 插槽,用于插入具体的子菜单项内容 -->
<slot />
</el-submenu>
</template>
VabSideBarItem.vue
表示整个侧边栏的组件
<!-- 表示整个侧边栏的组件 -->
<template>
<component
// 动态渲染组件,包含子菜单的菜单项[VabSubmenu.vue]或展示页面的菜单项[VabMenuItem.vue]
:is="menuComponent"
// 如果菜单项hidden属性为真,则不渲染
v-if="!item.hidden"
// 剩余属性都用于将值传给动态组件,以用于 子组件的逻辑或显示
:full-path="fullPath"
:item="item"
:route-children="routeChildren"
>
<!-- 如果当前菜单项有子菜单项,则递归渲染 VabSideBarItem 组件 -->
<template v-if="item.children && item.children.length">
<vab-side-bar-item
// 遍历子菜单数组,给每个子菜单渲染 VabSideBarItem 组件
v-for="route in item.children"
// 剩余的用于传递给动态组件
:key="route.path"
:full-path="handlePath(route.path)"
:item="route"
/>
</template>
</component>
</template>
<script>
export default {
......
computed: {
// 动态确定渲染的组件类型(VabMenuItem 或 VabSubmenu)
menuComponent() {},
}
methods: {
// 处理子菜单项的显示逻辑
handleChildren(children = [], parent) {
...
// 通过 filter 方法过滤需要显示的子菜单项
const showChildren = children.filter((item) => {})
// 如果只有一个需要显示的子菜单项,返回 true
if (showChildren.length === 1) {}
// 如果没有需要显示的子菜单项,设置一个虚拟的子菜单项,并返回 true
if (showChildren.length === 0) {}
// 如果有多个需要显示的子菜单项,返回 false
return false
},
// 处理路由路径
handlePath(routePath) {},
},
</script>
index.vue
<template>
<!-- 使用 Element UI 的 el-scrollbar 组件创建一个滚动容器;样式类根据collapse动态设置 -->
<el-scrollbar :class="{ 'is-collapse': collapse }" class="side-bar-container">
<!-- 用于显示应用的logo -->
<vab-logo />
<!-- 使用 el-menu 组件,用于创建垂直菜单 -->
<el-menu ... >
<!-- 通过v-for遍历路由数组,为每个路由生成vab-side-bar-item组件 -->
<template v-for="route in routes" >
<!-- tips -->
<vab-side-bar-item
:key="route.path"
:full-path="route.path"
:item="route"
/>
</template>
</el-menu>
</el-scrollbar>
</template>
<script>
...
export default {
name: 'VabSideBar',
data() {
return {
// 用于配置侧边栏是否具有唯一打开的子菜单
uniqueOpened,
}
},
computed: {
// 将 store 中的 getter 映射到局部计算属性;store是一个容器,是vuex中的概念
...mapGetters({}),
// 根据 collapse 的值返回不同的默认展开项
defaultOpens() {},
// 用于确定当前活动的菜单项。它检查当前路由的元信息中是否包含 activeMenu,如果有则返回该值,否则返回当前路由的路径
activeMenu() {},
// 返回导入的样式文件中的样式变量
variables() {},
},
}
</script>
tips:需要注意的是以Vue3启动这个项目,:key会报错;这是因为在Vue3中,:key应该放在
template
中解决方法:禁用插件 Vuter,使用插件 Volar;在根目录下添加文件
jsconfig.json
,添加内容:{ "vueCompilerOptions": { "experimentalCompatMode": 2 }, }
虽然显示该值以弃用,但也只好这样解决;解决方法参考:
zheyi420
VabTabsBar 标签栏
实现标签栏(Tabs Bar)的功能,即网页上方每个模块的标签
index.vue
<template>
<!-- 标签栏容器 -->
<div id="tabs-bar-container" class="tabs-bar-container">
<!-- 使用 Element UI 的 el-tabs 组件 -->
<el-tabs ... >
<!-- 遍历访问过的路由,生成标签页 -->
<el-tab-pane ... ></el-tab-pane>
</el-tabs>
<!-- 更多操作的下拉菜单 -->
<el-dropdown @command="handleCommand">
...
<!-- 更多操作的具体选项 -->
<el-dropdown-menu slot="dropdown" class="tabs-more">
...
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
...
export default {
...
// 监听路由变化
watch: {},
// 组件挂载后的生命周期钩子
mounted() {},
methods: {
// 处理关闭标签页事件
async handleTabRemove(tabActive) {},
// 处理点击标签事件
handleTabClick(tab) {},
// 初始化标签页
inittabs() {},
// 添加标签页
addtabs() {},
// 处理下拉菜单命令
handleCommand(command) {},
// 刷新路由
async refreshRoute() {},
// 关闭选定标签
async closeSelectedTag(view) {},
// 关闭其他标签
async closeOtherstabs() {},
async closeLefttabs() {},
async closeRighttabs() {},
// 关闭所有标签页
async closeAlltabs() {},
// 跳转到最后一个标签页
toLastTag(visitedRoutes, view) {},
// 跳转到当前标签页
async toThisTag() {},
},
}
</script>
VabTopBar 顶部导航栏
顶部导航栏,与VabSideBar对应,用于不同主题
index.vue
<!-- 顶部导航栏,与VabSideBar对应,用于不同主题 -->
<template>
<div class="top-bar-container">
<div class="vab-main">
<!-- 行布局 -->
<el-row>
<!-- 显示Logo -->
<el-col :lg="7" :md="7" :sm="7" :xl="7" :xs="7">
...
</el-col>
<!-- 展示导航菜单 -->
<el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
...
</el-col>
<!-- 右侧展示头像等组件 -->
<el-col :lg="5" :md="5" :sm="5" :xl="5" :xs="5">
...
</el-col>
</el-row>
</div>
</div>
</template>
<script>
...
export default {
name: 'VabTopBar',
data() {
return {
// 控制按钮脉冲动画的标志
pulse: false,
// 菜单触发方式,这里设置为鼠标悬浮触发
menuTrigger: 'hover',
}
},
computed: {
...
// 计算属性,获取当前激活的菜单项
activeMenu() {},
// 获取样式变量
variables() {},
},
methods: {
// 刷新路由的方法
async refreshRoute() {
// 发送自定义事件,通知重新加载路由视图
this.$baseEventBus.$emit('reload-router-view')
// 启动按钮脉冲动画
this.pulse = true
// 1秒后关闭按钮脉冲动画,即刷新按钮的转圈时间
setTimeout(() => {
this.pulse = false
}, 1000)
},
},
}
</script>
index.js
启动该项目时,控制台打印的信息
jsconfig.json
这是我自己设置的JS配置,用于启用兼容模式,避免``VabSideBar/index.vue
中
:key`的位置报错
{
"vueCompilerOptions": {
"experimentalCompatMode": 2
},
}
package.json
描述项目配置信息
prettier.config.js
配置 Prettier 工具的格式化规则
src 源代码
存放项目源代码
assets
存放项目的静态资源,这里存放的是图片
styles
css样式文件夹,该项目采用的是Scss样式
colorfulIcon
用于存放彩色图标的文件夹
svg
存放svg的文件夹
index.js
返回一个包含svg图像的数组
remixIcon
图标库
svg
存放svg图标的文件夹
index.js
动态引入svg图标
config 配置
配置文件
该文件夹内多数文件已经有注释,这里不再赘述
net.config.js
配置网络相关选项的文件
permission.js
权限控制
// 使用 NProgress 插件来展示页面加载进度条
VabProgress.configure({})
// 在每个路由切换前执行的全局前置守卫
router.beforeResolve(async (to, from, next) => {
// 如果开启了进度条,开始显示
if (progressBar) VabProgress.start()
// 获取用户的访问令牌
let hasToken = store.getters['user/accessToken']
// 如果未开启登录拦截,模拟有令牌
if (!loginInterception) hasToken = true
// 如果有令牌
if (hasToken) {
if (to.path === '/login') {
next({ path: '/' })
// 如果开启了进度条,结束显示
if (progressBar) VabProgress.done()
} else {
// 检查用户是否有权限
const hasPermissions = store.getters['user/permissions'] && store.getters['user/permissions'].length > 0
if (hasPermissions) {
next()
} else {
try {
let permissions
// 如果未开启登录拦截,创建虚拟权限
if (!loginInterception) {
//settings.js loginInterception为false时,创建虚拟权限
await store.dispatch('user/setPermissions', ['admin'])
permissions = ['admin']
} else {
// 获取用户信息,包括权限
permissions = await store.dispatch('user/getUserInfo')
}
let accessRoutes = []
// 根据身份验证模式设置路由
...
}
}
} else {
// 如果目标路由在白名单中,放行
if (routesWhiteList.indexOf(to.path) !== -1) {
next()
} else {
// 如果开启了记录路由,带上当前路由路径作为重定向参数跳转到登录页
...
}
}
document.title = getPageTitle(to.meta.title)
})
// 在每个路由切换后执行的全局后置守卫
router.afterEach(() => {
// 结束 NProgress 进度条
if (progressBar) VabProgress.done()
})
setting.config.js
默认通用配置
theme.config.js
主题配置
settings.js
默认配置 通用配置|主题配置|网络配置
index.js
导出 通用配置|主题配置|网络配置
plugins 插件
插件
echarts.js
图表库,用于在网页中创建丰富、交互式的数据可视化图表
element.js
初始化 UI 框架 Element UI
support.js
禁止使用IE浏览器
vabIcon.js
图标库,将
VabIcon
组件导入自VabIcon
库
index.js
公共引入和注册项目所需的依赖和配置
api 接口
存放与后端 API 交互的相关代码
ad.js
广告信息 接口
// 返回方式
{
"code": 200,
"msg": "",
"data": [
{
"_id": "60fbdf329c77390001ea7806",
"title": "年终大促,Max版本买1得4,Plus版本买1得2,点我购买",
"url": "https://vue-admin-beautiful.com/authorization"
}
]
}
changeLog.js
更新日志 接口
// 返回方式
{
"code": 200,
"msg": "",
"data": [
{
"_id": "60fd6dbecd84d60001f99f33",
"content": "在github上获得了第一个star,感恩一位名叫Bequiet2014的github用户。",
"timestamp": "2020-03-23"
},
]
}
colorfulIcon.js
处理与多彩图标相关的 API 请求
// 请求方式
return request({
url: '/colorfulIcon/getList',
method: 'post',
data,
})
github.js
用于处理GitHub API相关请求
// 用于获取指定的GitHub仓库
export function getRepos(params) {}
// 用于获取指定 GitHub 仓库的点赞(star)列表
export function getStargazers(params) {}
goodsList.js
商品列表相关的API请求
// 请求方式
return request({
url: '/goodsList/getList',
method: 'post',
data,
})
icon.js
获取图标的请求
// 请求方式
return request({
url: '/icon/getList',
method: 'post',
data,
})
markdown.js
包含与 Markdown 内容相关的 API 请求
// 请求方式
return request({
url: 'https://fastly.jsdelivr.net/gh/prettier/prettier@master/docs/options.md',
method: 'get',
})
menuManagement.js
菜单管理相关API
// 获取菜单树
export function getTree(data) {}
// 编辑菜单
export function doEdit(data) {}
// 删除菜单
export function doDelete(data) {}
notice.js
通知相关的 API 请求
// 返回方式
{
"code": 200,
"msg": "",
"data": [
{
"_id": "60fd73529b33ed00017eac32",
"title": "\n\t瑞雪兆丰年,红梅报新春,愿您新的一年平安喜乐,万事顺意,所得皆所愿!\n\t<a href='https://vue-admin-beautiful.com/admin-plus/' target='_blank'>admin-plus演示地址</a> <a href='https://vue-admin-beautiful.com/shop-vite/' target='_blank'>shop-vite演示地址</a>",
"closable": false,
"type": "success"
},
]
}
personalCenter.js
个人中心相关的 API 请求
// 获取列表
export function getList(data) {}
// 编辑操作
export function doEdit(data) {}
// 删除操作
export function doDelete(data) {}
publicKey.js
处理与公钥(public key)相关的 API 请求
// 请求方式
return request({
url: '/publicKey',
method: 'post',
})
remixIcon.js
包含与 Remix Icon 相关的 API 请求
// 请求方式
return request({
url: '/remixIcon/getList',
method: 'post',
data,
})
roleManagement.js
处理与角色管理相关的 API 请求
// 获取角色列表
export function getList(data) {}
// 编辑角色信息
export function doEdit(data) {}
// 删除角色
export function doDelete(data) {}
router.js
用于向后端发送获取路由信息的请求
// 请求方式
return request({
url: '/menu/navigate',
method: 'post',
data,
})
table.js
与表格数据相关的 API 请求
// 获取表格数据列表
export function getList(data) {}
// 执行编辑操作
export function doEdit(data) {}
// 执行删除操作
export function doDelete(data) {}
tree.js
包含与树形数据结构相关的 API 请求
// 请求方式
return request({
url: '/tree/list',
method: 'post',
data,
})
user.js
用户相关的API请求
// 用户登录
export async function login(data) {
// 如果启用了 RSA 登录,则对数据进行加密
if (loginRSA) {
data = await encryptedData(data)
}
...
}
// 获取用户信息函数
export function getUserInfo(accessToken) {}
// 用户登出函数
export function logout() {}
// 用户注册函数
export function register() {}
userManagement.js
用户管理相关的 API 请求
// 获取用户列表的 API 请求
export function getList(data) {}
// 编辑用户信息的 API 请求
export function doEdit(data) {}
// 删除用户的 API 请求
export function doDelete(data) {}
components 组件
用于存放可复用组件
SelectTree
下拉菜单组件
index.vue
<template>
<div class="select-tree-template">
<!-- 下拉选择框组件 -->
<el-select
v-model="selectValue"
class="vab-tree-select"
// 是否显示清空按钮
:clearable="clearable"
// 多选时是否折叠标签
:collapse-tags="selectType == 'multiple'"
// 是否支持多选
:multiple="selectType == 'multiple'"
// 指定树节点的唯一标识属性为 id
value-key="id"
// 清空按钮点击事件
@clear="clearHandle"
// 多选模式下移除标签事件
@remove-tag="removeTag"
>
<!-- 具体的选项 -->
<el-option :value="selectKey">
<el-tree
id="treeOption"
ref="treeOption"
// 当前选中节点的 key
:current-node-key="currentNodeKey"
// 树形结构的数据
:data="treeOptions"
// 默认勾选的节点的 key
:default-checked-keys="defaultSelectedKeys"
// 默认展开的节点的 key
:default-expanded-keys="defaultSelectedKeys"
// 是否高亮当前节点
:highlight-current="true"
// 节点的唯一标识属性
node-key="id"
// 配置节点的属性
:props="defaultProps"
// 是否显示复选框
:show-checkbox="selectType == 'multiple'"
// 复选框状态改变时的事件
@check="checkNode"
// 节点被点击时的事件
@node-click="nodeClick"
/>
</el-option>
</el-select>
</div>
</template>
<script>
export default {
name: 'SelectTreeTemplate',
// 组件接收的属性
props: {},
// 组件的数据
data() {},
// 组件的生命周期钩子
mounted() {},
methods: {
// 初始化树的值
initTree() {},
// 清除选中
clearHandle() {},
/* 清空选中样式 */
clearSelected() {},
// select多选时移除某项操作
removeTag() {},
// 点击叶子节点
nodeClick(data) {},
// 节点选中操作
checkNode() {},
},
}
</script>
VabCharge
动态效果组件
index.vue
<template>
<div class="content">
<!-- 渲染动态效果的容器,样式由外部传入 -->
<div class="g-container" :style="styleObj">
<!-- 显示动态数字的元素 -->
<div class="g-number">
{{ endVal }}
</div>
<!-- 背景动效容器 -->
<div class="g-contrast">
<!-- 旋转的圆圈 -->
<div class="g-circle"></div>
<!-- 移动的气泡 -->
<ul class="g-bubbles">
<li v-for="(item, index) in 15" :key="index"></li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default{
...
data() {
return {
decimals: 2, // 小数位数
prefix: '', // 数字前缀
suffix: '%', // 数字后缀
separator: ',', // 数字分隔符
duration: 3000, // 动画持续时间
}
},
...
}
</script>
VabProfile
显示用户个人资料组件
index.vue
<template>
<div class="card" :style="styleObj">
<!-- 卡片边框 -->
<div class="card-borders">
...
</div>
<!-- 卡片内容区域 -->
<div class="card-content">
...
</div>
<!-- 社交图标区域 -->
<div class="social-icons">
<!-- 循环渲染每个社交图标链接 -->
<a v-for="(item, index) in iconArray" :key="index" class="social-icon" :href="item.url" target="_blank">
<!-- 使用自定义组件显示 Font Awesome 图标 -->
<vab-icon :icon="['fas', item.icon]" />
</a>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'VabProfile',
// 接收父组件传递的属性
props: {
// 自定义样式对象
styleObj: {},
// 用户名
username: {},
// 用户头像 URL
avatar: {},
// 社交图标数组,包含图标名称和链接
iconArray: {},
},
...
}
</script>
VabSnow
雪花效果组件
index.vue
<template>
<div class="content" :style="styleObj">
<!-- 通过for循环创建200个雪花元素 -->
<div v-for="(item, index) in 200" :key="index" class="snow"></div>
</div>
</template>
VabUpload
上传文件的组件
index.vue
<template>
<!-- 弹窗组件 -->
<el-dialog ...>
<div class="upload">
<!-- 提示信息 -->
<el-alert ... />
<br />
<!-- 文件上传组件 -->
<el-upload
ref="upload"
// 指定允许上传的文件类型,这里限定为图片类型
accept="image/png, image/jpeg"
// 指定上传的接口地址或方法
:action="action"
// 是否自动上传,这里设置为false,表示手动触发上传
:auto-upload="false"
class="upload-content"
// 是否在点击弹窗外部区域关闭弹窗,这里设置为false,表示点击外部区域不关闭弹窗
:close-on-click-modal="false"
// 上传时附带的额外参数
:data="data"
// 已上传文件列表,通常用于回显文件列表
:file-list="fileList"
// 设置请求头
:headers="headers"
// 限制文件数量
:limit="limit"
// 文件列表的展示方式,这里是图片卡片形式
list-type="picture-card"
// 是否支持多选文件
:multiple="true"
// 上传的文件字段名
:name="name"
// 选择文件时触发的事件,通常用于更新组件状态
:on-change="handleChange"
// 上传失败时触发的事件
:on-error="handleError"
// 文件数量超过限制时触发的事件
:on-exceed="handleExceed"
// 点击预览图时触发的事件
:on-preview="handlePreview"
// 上传进度变化时触发的事件
:on-progress="handleProgress"
// 移除文件时触发的事件
:on-remove="handleRemove"
// 上传成功时触发的事件
:on-success="handleSuccess"
>
<i slot="trigger" class="el-icon-plus"></i>
<!-- 大图预览弹窗 -->
<el-dialog ...>
</el-dialog>
</el-upload>
</div>
<!-- 弹窗底部 -->
<div ...>
<!-- 上传进度提示 -->
<div ...>
</div>
<!-- 弹窗底部按钮 -->
<el-button type="primary" @click="handleClose">关闭</el-button>
<el-button :loading="loading" size="small" style="margin-left: 10px" type="success" @click="submitUpload">开始上传</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
...
data() {
return {
show: false, // 是否显示上传状态信息
loading: false, // 是否正在上传中
dialogVisible: false, // 是否显示大图预览弹窗
dialogImageUrl: '', // 大图预览的图片地址
action: 'https://vab-unicloud-3a9da9.service.tcloudbase.com/upload', // 上传接口地址
headers: {}, // 请求头
fileList: [], // 已上传文件列表
picture: 'picture', // 图片类型
imgNum: 0, // 当前已上传图片数量
imgSuccessNum: 0, // 当前上传成功的图片数量
imgErrorNum: 0, // 当前上传失败的图片数量
typeList: null, // 文件类型列表
title: '上传', // 弹窗标题
dialogFormVisible: false, // 弹窗是否可见
data: {}, // 弹窗附带的数据
}
},
computed: {
// 计算上传进度百分比
percentage() {},
},
methods: {
// 提交上传
submitUpload() {},
// 处理上传进度
handleProgress() {},
// 处理选择文件时的事件
handleChange(file, fileList) {},
// 处理上传成功时的事件
handleSuccess(response, file, fileList) {},
// 处理移除文件时的事件
handleRemove() {},
// 处理预览文件时的事件
handlePreview(file) {},
// 处理文件数量超过限制时的事件
handleExceed(files, fileList) {},
// 打开上传弹窗的事件
handleShow(data) {},
// 关闭上传弹窗的事件
handleClose() {},
},
}
</script>
layouts
组件化展示
components
展示的组件
VabAd
广告组件
index.vue
<template>
<div class="vab-ad">
<!-- 使用 Element UI 的轮播组件 -->
<el-carousel ...>
<el-carousel-item v-for="(item, index) in adList" :key="index">
<!-- 广告标签 -->
<el-tag type="warning">Ad</el-tag>
<!-- 广告链接,根据数据动态生成 -->
<a :href="item.url" target="_blank">{{ item.title }}</a>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
// 导入ad组件
import { getList } from '@/api/ad'
export default {
name: 'VabAd',
data() {
return {
// 存储环境变量 NODE_ENV 的值
nodeEnv: process.env.NODE_ENV,
// 存储广告列表数据
adList: [],
}
},
created() {
// 调用 fetchData 方法获取数据
this.fetchData()
},
methods: {
// 异步方法,用于获取广告列表数据
async fetchData() {
const { data } = await getList()
// 将获取的数据赋值给 adList
this.adList = data
},
},
}
</script>
VabAppMain
页面主要信息
index.vue
<script>
export default {
name: 'VabAppMain',
data() {
return {
// 是否显示 GitHub 角落
show: false,
// 当前年份
fullYear: new Date().getFullYear(),
// 版权信息
copyright,
// 页面标题
title,
// keep-alive 最大缓存数
keepAliveMaxNum,
// 是否显示路由视图
routerView: true,
// 是否显示底部版权信息
footerCopyright,
}
},
computed: {
...mapGetters({}),
// 计算需要缓存的路由数组
cachedRoutes() {},
// 计算 key,用于 keep-alive 的缓存判断
key() {},
},
// 监听 $route 变化,处理移动设备的侧边栏折叠
watch: {},
created() {
//重载所有路由
this.$baseEventBus.$on('reload-router-view', () => {})
},
mounted() {},
methods: {
// 调用 Vuex 中的 foldSideBar 方法,折叠侧边栏
...mapActions({}),
},
}
</script>
VabAvatar
管理员信息显示
index.vue
在头像的下拉菜单中,可以添加计算属性
personalCenter
,可以跳转到个人中心页面,但由于没有制作页面的具体信息,就没有放上去
VabBreadcrumb
面包屑组件,用于路由导航
index.vue
<template>
<!-- Element UI 面包屑组件 -->
<el-breadcrumb class="breadcrumb-container" separator=">">
<!-- 遍历路由匹配项,渲染面包屑项 -->
<el-breadcrumb-item v-for="item in list" :key="item.path">
{{ item.meta.title }}
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script>
export default {
name: 'VabBreadcrumb',
data() {
return {
// 初始化面包屑数据
list: this.getBreadcrumb(),
}
},
// 监听 $route 变化,更新面包屑数据
watch: {},
methods: {
// 获取面包屑数据的方法
getBreadcrumb() {
// 过滤路由匹配项,保留有名称和标题的项
return this.$route.matched.filter((item) => item.name && item.meta.title)
},
},
}
</script>
VabLogo
Logo展示
index.vue
<template>
<div :class="'logo-container-' + layout">
<!-- 路由链接,点击跳转到首页 -->
<router-link to="/">
<!-- 根据条件渲染 Remix 图标 -->
<vab-remix-icon v-if="logo" :icon-class="logo" class="logo" />
<!-- 标题文字 -->
<span :class="{ 'hidden-xs-only': layout === 'horizontal' }" :title="title" class="title">
{{ title }}
</span>
</router-link>
</div>
</template>
<script>
export default {
name: 'VabLogo',
data() {},
// 计算属性,获取 Vuex 中的 logo 和 layout 数据
computed: {
...mapGetters({
logo: 'settings/logo',
layout: 'settings/layout',
}),
},
}
</script>
VabNavBar
导航栏展示
index.vue
<template>
<div class="nav-bar-container">
<!-- 使用 Element UI 的行列布局 -->
<el-row :gutter="15">
<!-- 左侧面板,占据不同屏幕大小的比例 -->
<el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="4">
<!-- 展开/收起按钮,根据折叠状态设置图标和提示 -->
<div class="left-panel">
<i ...></i>
<vab-breadcrumb class="hidden-xs-only" />
</div>
</el-col>
<!-- 右侧面板,占据不同屏幕大小的比例 -->
<el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="20">
<div class="right-panel">
<!-- 错误日志组件 -->
<vab-error-log />
<!-- 全屏切换组件 -->
<vab-full-screen-bar @refresh="refreshRoute" />
<!-- 主题切换组件,仅在大屏幕下显示 -->
<vab-theme-bar class="hidden-xs-only" />
<!-- 重新加载所有路由图标,带有脉冲效果 -->
<vab-icon ... />
<!-- 用户头像组件 -->
<vab-avatar />
</div>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: 'VabNavBar',
data() {},
// 计算属性,获取 Vuex 中的一些状态数据
computed: {},
methods: {
...mapActions({}),
// 处理折叠状态的方法
handleCollapse() {},
// 刷新路由的方法
async refreshRoute() {},
},
}
</script>
VabThemeBar
主题侧边栏展示
index.vue
<template>
<span v-if="themeBar">
<!-- 主题配置图标 -->
<vab-icon :icon="['fas', 'palette']" title="主题配置" @click="handleOpenThemeBar" />
<div class="theme-bar-setting">
<!-- 主题配置按钮 -->
<div @click="handleOpenThemeBar">
<vab-icon :icon="['fas', 'palette']" />
<p>主题配置</p>
</div>
<!-- 拷贝源码按钮 -->
<div @click="handleGetCode">
<vab-icon :icon="['fas', 'laptop-code']"></vab-icon>
<p>拷贝源码</p>
</div>
</div>
<!-- 主题配置侧边栏 -->
<el-drawer :visible.sync="drawerVisible" append-to-body direction="rtl" size="300px" title="主题配置">
<el-scrollbar style="height: 80vh; overflow: hidden">
<!-- 主题配置表单 -->
<div class="el-drawer__body">
<el-form ...>
......
</el-form>
</div>
</el-scrollbar>
<!-- 主题配置侧边栏底部按钮 -->
<div class="el-drawer__footer">
...
</div>
</el-drawer>
</span>
</template>
<script>
export default {
...
methods: {
...mapActions({}),
// 判断是否是移动端
handleIsMobile() {},
// 打开主题设置侧边栏
handleOpenThemeBar() {},
// 将主题配置应用到系统中
handleSetTheme() {},
// 保存主题设置
handleSaveTheme() {},
// 恢复默认主题设置
handleSetDfaultTheme() {},
// 获取当前页面的源代码链接
handleGetCode() {},
},
}
</script>
EmptyLayout.vue
空的页面布局,用于渲染匹配当前路由的组件
export.js
导出组件的JS文件
index.vue
展示不同布局的页面
<template>
<div :class="classObj" class="vue-admin-beautiful-wrapper">
<!-- 水平布局 -->
<div ...>
...
</div>
<!-- 垂直布局 -->
<div ...>
...
</div>
<!-- 返回顶部按钮 -->
<el-backtop />
</div>
</template>
<script>
export default {
name: 'Layout',
data() {
return { oldLayout: '' }
},
computed: {
// 映射 Vuex 中的 getters
...mapGetters({}),
// 动态计算 classObj 对象
classObj() {},
},
// 生命周期钩子 - 组件挂载前
beforeMount() {},
// 生命周期钩子 - 组件销毁前
beforeDestroy() {},
// 生命周期钩子 - 组件挂载后
mounted() {},
methods: {
// 映射 Vuex 中的 actions
...mapActions({}),
// 判断是否为移动端
handleIsMobile() {},
// 处理窗口大小变化事件
handleResize() {},
},
}
</script>
router
router全局配置
index.js
// 登录、注册、错误页面,不需要在导航菜单中显示
export const constantRoutes = []
// 异步路由配置,用户登录后根据其权限动态加载
export const asyncRoutes = [
...
{
// 配置
path: '/personnelManagement',
component: Layout,
redirect: 'noRedirect',
name: 'PersonnelManagement',
meta: { title: '配置', icon: 'users-cog', permissions: ['admin'] },
children: [
{
// 用户管理
path: 'userManagement',
name: 'UserManagement',
component: () => import('@/views/personnelManagement/userManagement/index'),
meta: { title: '用户管理' },
},
{
// 角色管理
path: 'roleManagement',
name: 'RoleManagement',
component: () => import('@/views/personnelManagement/roleManagement/index'),
meta: { title: '角色管理' },
},
{
// 菜单管理
path: 'menuManagement',
name: 'MenuManagement',
component: () => import('@/views/personnelManagement/menuManagement/index'),
meta: { title: '菜单管理', badge: 'New' },
},
],
},
...
]
// 管理整个应用的路由
const router = new VueRouter({})
// 重新加载页面
export function resetRouter() {}
store
存放状态管理相关的代码
modules
模块化代码
errorLog.js
异常捕获的状态拦截
// 定义了模块的状态
const state = () => ({})
// 获取模块状态
const getters = {}
// 同步操作
const mutations = {}
// 异步操作
const actions = {
// 添加异常日志
addErrorLog({ commit }, errorLog) {},
// 清空异常日志数组
clearErrorLog({ commit }) {},
}
// 导出模块
export default { state, getters, mutations, actions }
routes.js
路由拦截状态管理
// 返回模块的初始状态
const state = () => ({
routes: [],
partialRoutes: [],
})
// 获取模块状态
const getters = {
routes: (state) => state.routes,
partialRoutes: (state) => state.partialRoutes,
}
// 同步处理
const mutations = {
// intelligence模式 智能模式
setRoutes(state, routes) {
state.routes = constantRoutes.concat(routes)
},
// all模式
setAllRoutes(state, routes) {
state.routes = constantRoutes.concat(routes)
},
// partialRoutes模式
setPartialRoutes(state, routes) {
state.partialRoutes = constantRoutes.concat(routes)
},
}
// 异步处理
const actions = {},
}
export default { state, getters, mutations, actions }
settings.js
全局配置的状态管理
// 获取默认配置
const { tabsBar, logo, layout, header, themeBar } = defaultSettings
// 通过 localStorage 获取之前保存的主题配置
const theme = JSON.parse(localStorage.getItem('vue-admin-beautiful-theme')) || ''
// 初始化状态
const state = () => ({})
// 获取状态
const getters = {}
// 修改状态 同步
const mutations = {}
// 触发mutations操作 异步
const actions = {}
export default { state, getters, mutations, actions }
table.js
代码生成机状态管理
作用不明
tabsBar.js
多标签页逻辑
const mutations = {
// 添加访问过的路由
addVisitedRoute(state, route) {
// 查找目标路由
let target = state.visitedRoutes.find((item) => item.path === route.path)
if (target) {
// 如果新路由的完整路径不同于目标路由的完整路径,进行属性合并
if (route.fullPath !== target.fullPath) Object.assign(target, route)
return
}
// 如果未找到目标路由,将新路由添加到访问过的路由列表中
state.visitedRoutes.push(Object.assign({}, route))
},
// 删除指定路由
delVisitedRoute(state, route) {
state.visitedRoutes.forEach((item, index) => {
// 查找并删除匹配的路由
if (item.path === route.path) state.visitedRoutes.splice(index, 1)
})
},
// 删除除指定路由外的所有路由
delOthersVisitedRoute(state, route) {},
// 删除指定路由左侧的所有路由
delLeftVisitedRoute(state, route) {},
// 删除指定路由右侧的所有路由
delRightVisitedRoute(state, route) {},
// 删除所有非固定路由(meta.affix 为 true)的路由
delAllVisitedRoutes(state) {},
// 更新指定路由的信息
updateVisitedRoute(state, route) {
state.visitedRoutes.forEach((item) => {
// 查找匹配的路由并更新信息
if (item.path === route.path) item = Object.assign(item, route)
})
},
}
user.js
登录信息accessToken逻辑
const actions = {
// 设置权限
setPermissions({ commit }, permissions) {
commit('setPermissions', permissions)
},
// 异步处理登录逻辑
async login({ commit }, userInfo) {},
// 异步处理获取用户信息逻辑
async getUserInfo({ commit, state }) {},
// 异步处理退出登录逻辑
async logout({ dispatch }) {},
// 重置访问令牌
resetAccessToken({ commit }) {},
}
index.js
整合所有 vuex 模块,再导出
Vue.use(Vuex)
// 使用 require.context 导入 './modules' 目录下的所有以 .js 结尾的文件
const files = require.context('./modules', false, /\.js$/)
const modules = {}
// 遍历所有导入的模块文件,将其加入到 modules 对象中
files.keys().forEach((key) => {
modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
})
// 为所有模块添加 namespaced:true 属性,用于解决 Vuex 命名冲突问题
Object.keys(modules).forEach((key) => {
modules[key]['namespaced'] = true
})
// 创建 Vuex 实例,将所有模块加入到 store 中
const store = new Vuex.Store({
modules,
})
// 导出 store 实例
export default store
utils
存放通用工具函数
accessToken
处理accessToken
// 获取accessToken
export function getAccessToken() {
// 检查是否配置了存储方式
if (storage) {
// 根据存储方式返回相应的accessToken
if ('localStorage' === storage) {
return localStorage.getItem(tokenTableName)
} else if ('sessionStorage' === storage) {
return sessionStorage.getItem(tokenTableName)
} else {
// 如果存储方式未正确配置,默认使用localStorage
return localStorage.getItem(tokenTableName)
}
} else {
return localStorage.getItem(tokenTableName)
}
}
// 存储accessToken
export function setAccessToken(accessToken) {}
// 移除accessToken
export function removeAccessToken() {}
clipboard.js
封装了复制功能
encrypt.js
封装了加密功能
const privateKey =''
// RSA加密
export async function encryptedData(data) {
let publicKey = ''
// 从后端获取公钥
const res = await getPublicKey()
publicKey = res.data.publicKey
...
// 创建 JSEncrypt 实例,设置公钥,并进行加密
const encrypt = new JSEncrypt()
encrypt.setPublicKey(`-----BEGIN PUBLIC KEY-----${publicKey}-----END PUBLIC KEY-----`)
data = encrypt.encrypt(JSON.stringify(data))
// 返回包含加密后数据的对象
return {
param: data,
}
}
// RSA解密
export function decryptedData(data) {}
errorLog.js
配置错误日志处理
// 获取是否需要记录错误日志的配置
const needErrorLog = errorLog
// 检查是否需要记录错误日志的函数
const checkNeed = () => {}
// 记录错误日志
if (checkNeed()) {
// 设置 Vue 的全局错误处理函数
Vue.config.errorHandler = (err, vm, info) => {
// 打印错误信息到控制台
console.error('vue-admin-beautiful错误拦截:', err, vm, info)
// 获取当前页面的 URL
const url = window.location.href
// 等待 Vue 渲染完成后,将错误信息记录到 Vuex 的错误日志中
Vue.nextTick(() => {
store.dispatch('errorLog/addErrorLog', { err, vm, info, url })
})
}
}
handleRoutes.js
处理路由
作用不明
pageTitle.js
设置页面标题
// 如果传入了页面标题,则拼接页面标题和全局标题;否则返回全局标题
if (pageTitle) return `${pageTitle}-${title}`
permission.js
检查权限
export default function checkPermission(value) {
// 检查传入的值是否为非空数组
if (value && value instanceof Array && value.length > 0) {
// 获取用户当前拥有的所有权限
const permissions = store.getters['user/permissions']
// 需要检查的权限数组
const permissionPermissions = value
// 判断用户是否拥有其中任一权限
return permissions.some((role) => {
return permissionPermissions.includes(role)
})
} else {
// 如果传入的值不是非空数组,返回false
return false
}
}
request.js
request请求处理
static.js
使用 Mock.js 模拟接口响应
vab.js
全局组件
validate.js
用于字符串验证的JS
index.js
存储常用工具的JS
views
视图界面
由于结构较为清晰,这里不做详细解释
App.vue
Vue项目的根组件
main.js
Vue.js 应用程序的入口文件