目录
├── .husky -- husky 勾子
| ├── commit-msg -- git commit规范检查代码
| ├── pre-commit -- git commit前检查代码
├── .vscode -- vscode配置目录
├── bin -- 可执行文件目录
| ├── build.bat -- 打包工程 == npm run build
| ├── package.bat -- 安装 npm 依赖包 == npm install
| └── run-web.bat -- 开发模式上启动工程 == npm run serve
├── public -- 静态资源文件目录
├── src -- 源码目录
| ├── api -- 接口文件目录
| | ├── system -- 系统配置接口目录
| | ├── login.js -- 登录接口
| | └── menu.js -- 获取动态菜单接口
| ├── assets -- 资源目录
| | ├── 401_images -- 401页面文件图片目录
| | ├── 404_images -- 404页面文件图片目录
| | ├── icons -- svg图标目录
| | ├── images -- 图片目录
| | ├── logo -- 工程logo
| | └── styles -- 样式目录
| ├── components -- 组件目录
| ├── directive -- 指令目录
| | ├── dialog -- 模态框指令
| | ├── module -- 剪切板指令
| | ├── permission -- 权限指令
| | └── index.js -- 入口文件
| ├── layout -- 布局组件目录
| ├── mock -- 模拟接口数据目录
| ├── plugins -- 插件目录
| | ├── auth.js -- 权限功能插件
| | ├── cache.js -- 本地存储功能插件
| | ├── download.js -- 下载功能插件
| | ├── index.js -- 入口文件
| | ├── modal.js -- 模态框相关功能插件(提示框、信息框、确认框等等)
| | └── tab.js -- 页签功能插件(页签全部关闭,其它关闭,右侧关闭,左侧关闭等等)
| ├── router -- 路由组件目录
| ├── store -- 状态管理目录
| ├── utils -- 常用工具类目录
| ├── views -- 页面目录
| ├── App.vue -- App.vue 文件
| ├── main.js -- main.js 文件
| ├── permission.js -- 路由守卫配置文件
| └── settings -- 工程右侧边栏配置文件
├── .browserslistrc -- browserslist配置文件
├── .editorconfig -- editorconfig配置文件
├── .env.development -- 工程开发环境配置文件
├── .env.production -- 工程生产环境配置文件
├── .eslintignore -- eslint忽略配置文件
├── .eslintrc.js -- eslint配置文件
├── .gitignore -- git配置文件
├── .npmnc -- npm配置文件
├── .prettierignore -- prettier忽略文件
├── .prettierrc.js -- prettier配置文件
├── babel.config.js -- babel配置文件
├── commitlint.config.js -- commit规范配置文件
├── jsconfig.json -- jsconfig配置文件
├── package.json -- package.json文件
├── README.md -- 本文件
└── vue.config.js -- 工程自定义配置文件
下面我对上面每个文件的作用进行一下简单讲解。
- .husky
husky是一个让git hooks更简单使用的工具库。
这个是版本7.x之后的husky配置目录,里面放置你定义的git hooks。如上图所示,我们定义了2个钩子:commit-msg和pre-commit。
commit-msg:检查git commit -m "我是被检查的信息"的信息是否符合规范;
pre-commit:git commit提交之前执行的操作,比如可以执行npm run test、npm run lint,具体命令可*配置。
在这里我说两句它们的执行顺序。
当我们执行 git commit -m "xxxx"时,husky进行检查,发现有2个钩子,因为我们执行的是commit,所以它会优先于commit执行pre-commit这个钩子,而这个钩子里,我们配置的是一个npm 命令:npm run lint-staged。这时会从package.json中找到对应的命令"lint-staged"执行。在这里会执行我们的代码风格检查。
当上述完成后,发现commit-msg这个钩子,然后执行这个它。它会判断我们的"xxxx"是否符合我们格式要求,符合之后才会提交。 - .vscode
这个是vs code编辑器的配置目录,在这里我们有2个文件:extensions.json和settings.json。
extensions.json: 配置了编辑器推荐的扩展插件与不推荐的扩展插件;
settings.json:对编辑器进行配置,我们在这里配置了统一的注释模板。 - bin
一个可执行命令的目录,这里有3个bat批处理文件,对一些npm命令进行简单封装。
build.bat: 等价于npm run build,完成项目打包;
package.bat: 等价于npm install --registry=registry.npm.taobao.org 使用淘宝镜像完成安装依赖;
run-web.bat: 等价于npm run serve,启动开发服务器。 - public
vue-cli命令行工具生成的静态资源目录,该目录的静态资源不会被webpack打包。 - src
源码目录,下面会详细介绍。 - .browserslistrc
为不同的前端工具提供一份共享的目标浏览器的配置。比如Babel, Autoprefixer等,发现该配置不包括IE浏览器,那么它们在生成代码时就可以忽略IE,只为指定的浏览添加腻子脚本。 - .editorconfig
统一编辑器的一些配置,比如字符集、缩进风格等。vscode需要安装指定的插件。 - .env.development
开发环境下配置文件,即我们npm run serve启动开发服务器时,一些变量的配置都是在这里完成的。比如请求的统一前缀等等。 - .env.production
生成环境配置文件,与上述.env.development一样,当我们执行npm run build时,这里的配置将生效。 - .eslintignore
eslint忽略文件,如果不想让eslint对某些文件或目录生效,可以在这里配置。 - .eslintrc.js
eslint配置文件。eslint是一个前端js代码检测工具。 - .gitignore
git忽略文件。 - .npmrc
npm配置文件,可以配置私服地址、代理服务器地址等等。 - .prettierignore
prettier忽略文件。 - .prettierrc.js
prettier配置文件。prettier是一个前端代码格式化工具。prettier只专注于格式,比如函数名称前后是否有空格、单引号还是双引号、要不要结尾分号等,它不会改变源码;而eslint是源码检查,比如==应改为===、const代替var等等,它可能会改变你的源码。 - babel.config.js
babel配置文件。babel是一个js编译器,可以将浏览器不支持的高级js语法转换成其支持的低版本js代码。 - commitlint.config.js
commitlint配置文件。就是检查git commit信息是否符合规范的工具的配置文件。 - jsconfig.json
jsconfig.json由tsconfig.json衍生而来,表明该目录是js项目的根目录,可以指定js语言服务提供的功能选项。如果有,可以优化vscode的编码体验,例如智能提示等,没有也不会影响代码质量。 - package.json
node项目包管理文件。 - README.md
说明文档。 - vue.config.js
vue-cli生成的脚手架工程的自定义配置文件。在这里可以配置反向代理、webpack插件、生成打包的配置选项等等。
下面说说src
- src/api
接口目录,项目页面调用的接口都统一在这里配置,只有少数接口是在页面中配置。比如上传文件组件,它需要配置一个后台接口地址,除了这种特殊情况,其它一律在这里配置,并尽量保障目录结构与页面目录结构一致,以方便快速查找。 - src/assets
静态资源目录,在这里可以放一些图片、svg、样式文件。考虑到svg的方便操作、可压缩伸缩等优势,以及项目已经对svg封装了通用组件,方便引用,请优先使用它。 - src/components
封装的通用组件,请熟悉它、熟悉它、熟悉它。一是尽量重用,提高代码利用率;二是防止组件碎片化。 - src/directive
自定义指令,是对vue内置指令的补充,可完成一些比较实现的操作,请熟悉其用法。 - src/layout
布局组件,负责整个项目的布局,主要在路由配置中使用,请小心修改。 - src/mock
mock目录,主要在无后台接口的情况下生成模拟数据。 - src/plugins
插件目录,主要是对element-ui一些提示组件的封装,方便页面引用。 - src/router
路由配置目录。在路由必须属性的基础上添加了一些自定义属性,方便生成菜单栏时使用。具体可以参考文件中相关注释。 - src/store
vuex配置目录。主要是一些全局配置和当前登录用户的配置信息。 - src/utils
工具类。index.js与ruoyi.js封装了一些无业务的工具方法,应着重掌握;其它工具类偏相于某一方面需要了解。 - src/views
页面目录。请尽量做到地址栏路由路径、页面目录结构、接口目录结构三者统一,方便快速查找。比如地址栏为xxx/system/users/1,那页面与接口目录结构也尽量为system/users,这样可避免去资源配置中查看某个路由对应的文件地址,提高效率。 - src/App.vue
vue 根组件。 - src/main.js
项目初始化,即入口文件。 - src/permission.js
权限文件,主要利用路由守卫功能实现权限管理。 - src/settings.js
项目布局配置文件,其值会作为默认值在vuex中初始化。
这里简单说说登录及权限流程。
- 当我们打开一个地址时,因为监测到地址栏变化了,即路由发生了变化,路由守卫功能开始执行。对应的代码为:src/permission.js。在这里我们发现它调用getToken()获取token。如果获取到了,则进入我们地址栏指定的页面;如果没有获取到,则进入登录页面,路由地址为"/login"。
- 登录页面为src/views/login.vue。这里需要注意的是,登录时没有调用相关的接口,而是调用了某个vuex的action。登录页面我们通过this.$store.dispatch('Login',xxx),调用了名为"Login"的Action。
- 现在我们进入src/store/modules/user.js,然后找到Login。这个方法调用了我们的后台接口,当请求成功后,它会保存token,过期时间,然后resolve(),即把控制权又交给我们第2步中调用它的方法。
- 当通过resolve()再次进入后,我们执行成功回调,这里只有一个功能,进入首页,路由为"/"。
- 通过查询路由文件src/router/index.js,我们知道"/"对应的文件为src/views/index.vue。当我们进入这个地址对应的页面时,路由又发生了变化,即由"/login"变成了"/"。这时,又被路由守卫拦截了,因为我们已经在第3步保存了token,这次我们进入有token的分支。这里又分了2个分支:如果有权限,直接进入页面;如果没有权限,则调用action。我们是第一次进入,没有角色权限,继续调用store.dispatch('GetInfo')。
- 通过调用名为"GetInfo"的action,我们又进入了文件src/store/modules/user.js。然后找到GetInfo方法,它调用了后台接口,请求用户信息,成功之后,我们保存了用户头像、角色、权限、名称等等,然后通过resolve(res)把执行权限交还给调用者。
- resolve(res)之后,我们又回到了src/permission.js文件,进入GetInfo的成功回调,在这里我们发现它又调用了一个action:store.dispatch('GenerateRoutes')。
- 通过调用名为"GenerateRoutes"的action,我们进入文件src/store/modules/permission.js。然后找到GenerateRoutes方法,它调用了后台接口,返回请求路由信息,成功之后,我们保存了当前登录用户能获取到的所有路由数据,我们保存这些路由数据,把它转换一下数据格式,方便我们的菜单组件渲染出它们。最后我们通过resolve(rewriteRoutes)把执行权限交还给调用者。
- resolve(rewriteRoutes)之后,我们又回到src/permission.js文件,进入GenerateRoutes的成功回调,在这里我们添加动态路由,然后通过next()进入我们的页面。至此,我们终于通过登录进入首页了。
- 当我们再进入其它时,因为我们已经有了token,有了角色信息,有了路由信息,我们就通过next()直接进入我们想要的页面了。
以上就是一个完整的登录流程。
下面说说如何配置路由,权限
通过跟踪上面第6步,我们知道,权限信息被保存在store/user模块下。为了验证,我们可以打开开发者工具,切换到Vue标签,找到Vuex进行查看。
从图中我看到,当前登录用户为admin;它的角色是一个数组,有一个admin角色;它的权限也是一个数组,权限是"::*"。
1. 添加目录时,我们要打开“系统管理/菜单管理”,选择新增
上级菜单:按需要选择即可,如果自己是*就选择为“主类目”;
菜单类型:若依的要求是“目录”嵌套“菜单”;“菜单”包含“按钮”;
菜单图标:略;
菜单名称:略;
显示排序:略;
是否外链:是,这将不会再包含子内容,当点击时,将打开它指定的外部地址;
路由地址:如果外链为是,则地址需为http(s)开头,即为外部地址;反之,则为项目内部路由地址。注:项目内部地址不需求以“/”开头。
显示菜单:控制菜单在左侧菜单栏的显示与隐藏;
菜单状态:控制菜单的状态。
2. 添加菜单
上级菜单:正常的选择时选择目录,如果你选择非目录时,会造成显示问题;
菜单类型:略;
菜单图标:略;
菜单名称:略;
显示排序:略;
是否外链:同上;
路由地址:同上;注意:这里地址不需要写上父级的名称,比如你想把路由定义为“/system/users”,因为父级已经指定为“system”了,所以这里只需要为“users”即可。若依会根据它所处的路径把它的父级自动加上。所以你想在一个目录下配置一个/foo是不成功的。
组件地址:views下的文件地址,比如说system/user/index
权限字符:就是给这个菜单定义一个权限名称,不能与其它重名;
路由参数:传递一些参数,一般不需要;
是否缓存:是,在标签打开中被缓存,当然该组件的名称也要正确;
是示状态:同上;
菜单状态:同上。
3. 添加按钮
上级菜单:同上,只能指定为菜单;
菜单类型:略;
菜单名称:略;
显示排序:略;
权限字符:给这个按钮定义一个名称,方便根据权限显示与隐藏它,名称唯一。
4. 最后我们看一下最终生成的图片
这样就完成了一个典型的目录、菜单、按钮添加。
如果我们查看若依的页面,会发现它的用户列表页面是一个独立的路由,而新增和修改只是依附与列表页面上的2个按钮显示出的弹框。那我们可以把新增也写成一个独立的路由吗?
答案是可以,但会造成路由配置冗长问题。
用户管理,也就是用户列表页面,现在是一个独立的路由,对应的组件为"system/user/index";
如果我们的新增也为一个独立路由,并且组件为"system/user/user-add"。
那我们这个配置在哪里呢?
能配置在用户管理下吗?
答案是不可以,因为用户管理是菜单,菜单只能包含按钮,如果包含菜单可能显示不出来。
那我们只能把这个配置的与“用户管理”平级,如果每个菜单都这样配置,这个配置列表将会特别长,并且也不利于我们给某个角色分配权限时选择相应的菜单权限,因为我可能只分配了新增与修改权限而遗忘了列表权限,但我无法进入列表页面,新增与修改也就没有意义了。
解决的办法只能是修改若依的源码,此外按下不表。
5. 按钮权限的使用
'system:user:add'是我们给新增按钮起的权限名称,也可以从第4步的截图中看出。
在这里v-hasPermi是我们自定义的一个指令,它的src/directive/permission/hasPermi.js源码如下:
import store from '@/store';
export default {
inserted(el, binding, vnode) {
const { value } = binding;
const allPermission = '*:*:*';
const permissions = store.getters && store.getters.permissions;
if (value && value instanceof Array && value.length > 0) {
const permissionFlag = value;
const hasPermissions = permissions.some((permission) => {
return allPermission === permission || permissionFlag.includes(permission);
});
if (!hasPermissions) {
el.parentNode && el.parentNode.removeChild(el);
}
} else {
throw new Error('请设置操作权限标签值');
}
},
};
如果我们有它指定的权限,或者我们的权限为'::*',则它会在页面显示;反之,它会被从页面中删除。这样就做到了按钮级权限分配。
菜单配置,权限按钮的使用就先介绍到这里,其它后面再补。