# 安诺镇痛开发文档 [TOC] <div class="theme-default-content content__default"> # [#](#前端手册) 前端手册 ## [#](#通用方法) 通用方法 ### [#](#tab对象) $tab对象 `$tab`对象用于做页签操作、刷新页签、关闭页签、打开页签、修改页签等,它定义在`plugins/tab.js`文件中,它有如下方法 * 打开页签 <div class="language-js line-numbers-mode"> this.$tab.openPage("用户管理", "/system/user"); this.$tab.openPage("用户管理", "/system/user").then(() => { // 执行结束的逻辑 }) </div> * 修改页签 <div class="language-js line-numbers-mode"> const obj = Object.assign({}, this.$route, { title: "自定义标题" }) this.$tab.updatePage(obj); this.$tab.updatePage(obj).then(() => { // 执行结束的逻辑 }) </div> * 关闭页签 <div class="language-js line-numbers-mode"> // 关闭当前tab页签,打开新页签 const obj = { path: "/system/user" }; this.$tab.closeOpenPage(obj); // 关闭当前页签,回到首页 this.$tab.closePage(); // 关闭指定页签 const obj = { path: "/system/user", name: "User" }; this.$tab.closePage(obj); this.$tab.closePage(obj).then(() => { // 执行结束的逻辑 }) </div> * 刷新页签 <div class="language-js line-numbers-mode"> // 刷新当前页签 this.$tab.refreshPage(); // 刷新指定页签 const obj = { path: "/system/user", name: "User" }; this.$tab.refreshPage(obj); this.$tab.refreshPage(obj).then(() => { // 执行结束的逻辑 }) </div> * 关闭所有页签 <div class="language-js line-numbers-mode"> this.$tab.closeAllPage(); this.$tab.closeAllPage().then(() => { // 执行结束的逻辑 }) </div> * 关闭左侧页签 <div class="language-js line-numbers-mode"> this.$tab.closeLeftPage(); const obj = { path: "/system/user", name: "User" }; this.$tab.closeLeftPage(obj); this.$tab.closeLeftPage(obj).then(() => { // 执行结束的逻辑 }) </div> * 关闭右侧页签 <div class="language-js line-numbers-mode"> this.$tab.closeRightPage(); const obj = { path: "/system/user", name: "User" }; this.$tab.closeRightPage(obj); this.$tab.closeRightPage(obj).then(() => { // 执行结束的逻辑 }) </div> * 关闭其他tab页签 <div class="language-js line-numbers-mode"> this.$tab.closeOtherPage(); const obj = { path: "/system/user", name: "User" }; this.$tab.closeOtherPage(obj); this.$tab.closeOtherPage(obj).then(() => { // 执行结束的逻辑 }) </div> ### [#](#modal对象) $modal对象 `$modal`对象用于做消息提示、通知提示、对话框提醒、二次确认、遮罩等,它定义在`plugins/modal.js`文件中,它有如下方法 * 提供成功、警告和错误等反馈信息 <div class="language-javascript line-numbers-mode"> this.$modal.msg("默认反馈"); this.$modal.msgError("错误反馈"); this.$modal.msgSuccess("成功反馈"); this.$modal.msgWarning("警告反馈"); </div> * 提供成功、警告和错误等提示信息 <div class="language-javascript line-numbers-mode"> this.$modal.alert("默认提示"); this.$modal.alertError("错误提示"); this.$modal.alertSuccess("成功提示"); this.$modal.alertWarning("警告提示"); </div> * 提供成功、警告和错误等通知信息 <div class="language-javascript line-numbers-mode"> this.$modal.notify("默认通知"); this.$modal.notifyError("错误通知"); this.$modal.notifySuccess("成功通知"); this.$modal.notifyWarning("警告通知"); </div> * 提供确认窗体信息 <div class="language-javascript line-numbers-mode"> this.$modal.confirm('确认信息').then(function() { ... }).then(() => { ... }).catch(() => {}); </div> * 提供遮罩层信息 <div class="language-javascript line-numbers-mode"> // 打开遮罩层 this.$modal.loading("正在导出数据,请稍后..."); // 关闭遮罩层 this.$modal.closeLoading(); </div> ### [#](#auth对象) $auth对象 `$auth`对象用于验证用户是否拥有某(些)权限或角色,它定义在`plugins/auth.js`文件中,它有如下方法 * 验证用户权限 <div class="language-javascript line-numbers-mode"> // 验证用户是否具备某权限 this.$auth.hasPermi("system:user:add"); // 验证用户是否含有指定权限,只需包含其中一个 this.$auth.hasPermiOr(["system:user:add", "system:user:update"]); // 验证用户是否含有指定权限,必须全部拥有 this.$auth.hasPermiAnd(["system:user:add", "system:user:update"]); </div> * 验证用户角色 <div class="language-javascript line-numbers-mode"> // 验证用户是否具备某角色 this.$auth.hasRole("admin"); // 验证用户是否含有指定角色,只需包含其中一个 this.$auth.hasRoleOr(["admin", "common"]); // 验证用户是否含有指定角色,必须全部拥有 this.$auth.hasRoleAnd(["admin", "common"]); </div> ### [#](#cache对象) $cache对象 `$cache`对象用于处理缓存。我们并不建议您直接使用`sessionStorage`或`localStorage`,因为项目的缓存策略可能发生变化,通过`$cache`对象做一层调用代理则是一个不错的选择。`$cache`提供`session`和`local`两种级别的缓存,如下: <table> <thead> <tr> <th>对象名称</th> <th>缓存类型</th> </tr> </thead> <tbody> <tr> <td>session</td> <td>会话级缓存,通过sessionStorage实现</td> </tr> <tr> <td>local</td> <td>本地级缓存,通过localStorage实现</td> </tr> </tbody> </table> **示例** <div class="language-javascript line-numbers-mode"> // local 普通值 this.$cache.local.set('key', 'local value') console.log(this.$cache.local.get('key')) // 输出'local value' // session 普通值 this.$cache.session.set('key', 'session value') console.log(this.$cache.session.get('key')) // 输出'session value' // local JSON值 this.$cache.local.setJSON('jsonKey', { localProp: 1 }) console.log(this.$cache.local.getJSON('jsonKey')) // 输出'{localProp: 1}' // session JSON值 this.$cache.session.setJSON('jsonKey', { sessionProp: 1 }) console.log(this.$cache.session.getJSON('jsonKey')) // 输出'{sessionProp: 1}' // 删除值 this.$cache.local.remove('key') this.$cache.session.remove('key') </div> ### [#](#download对象) $download对象 `$download`对象用于文件下载,它定义在`plugins/download.js`文件中,它有如下方法 * 根据名称下载`download`路径下的文件 <div class="language-javascript line-numbers-mode"> const name = "be756b96-c8b5-46c4-ab67-02e988973090.xlsx"; const isDelete = true; // 默认下载方法 this.$download.name(name); // 下载完成后是否删除文件 this.$download.name(name, isDelete); </div> * 根据名称下载`upload`路径下的文件 <div class="language-javascript line-numbers-mode"> const resource = "/profile/upload/2021/09/27/be756b96-c8b5-46c4-ab67-02e988973090.png"; // 默认方法 this.$download.resource(resource); </div> * 根据请求地址下载`zip`包 <div class="language-javascript line-numbers-mode"> const url = "/tool/gen/batchGenCode?tables=" + tableNames; const name = "ruoyi"; // 默认方法 this.$download.zip(url, name); </div> * 更多文件下载操作 <div class="language-javascript line-numbers-mode"> // 自定义文本保存 var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"}); this.$download.saveAs(blob, "hello world.txt"); // 自定义文件保存 var file = new File(["Hello, world!"], "hello world.txt", {type: "text/plain;charset=utf-8"}); this.$download.saveAs(file); // 自定义data数据保存 const blob = new Blob([data], { type: 'text/plain;charset=utf-8' }) this.$download.saveAs(blob, name) // 根据地址保存文件 this.$download.saveAs("https://ruoyi.vip/images/logo.png", "logo.jpg"); </div> ## [#](#开发规范) 开发规范 ### [#](#新增-view) 新增 view 在 [@/views<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui/src/views) 文件下 创建对应的文件夹,一般性一个路由对应一个文件, 该模块下的功能就建议在本文件夹下创建一个新文件夹,各个功能模块维护自己的`utils`或`components`组件。 ### [#](#新增-api) 新增 api 在 [@/api<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui/src/api) 文件夹下创建本模块对应的 api 服务。 ### [#](#新增组件) 新增组件 在全局的 [@/components<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui/src/components) 写一些全局的组件,如富文本,各种搜索组件,封装的分页组件等等能被公用的组件。 每个页面或者模块特定的业务组件则会写在当前 [@/views<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui/src/views) 下面。 如:`@/views/system/user/components/xxx.vue`。这样拆分大大减轻了维护成本。 ### [#](#新增样式) 新增样式 页面的样式和组件是一个道理,全局的 [@/style<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Cloud/tree/master/ruoyi-ui/src/assets/styles) 放置一下全局公用的样式,每一个页面的样式就写在当前 `views`下面,请记住加上`scoped` 就只会作用在当前组件内了,避免造成全局的样式污染。 <div class="language-css line-numbers-mode"> /* 编译前 */ .example { color: red; } /* 编译后 */ .example[_v-f3f3eg9] { color: red; } </div> ## [#](#请求流程) 请求流程 ### [#](#交互流程) 交互流程 一个完整的前端 UI 交互到服务端处理流程是这样的: 1. UI 组件交互操作; 2. 调用统一管理的 api service 请求函数; 3. 使用封装的 request.js 发送请求; 4. 获取服务端返回; 5. 更新 data; 为了方便管理维护,统一的请求处理都放在 `@/src/api` 文件夹中,并且一般按照 model 纬度进行拆分文件,如: <div class="language- line-numbers-mode"> api/ system/ user.js role.js monitor/ operlog.js logininfor.js ... </div> <div class="custom-block tip"> 提示 其中,[@/src/utils/request.js<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/blob/master/ruoyi-ui/src/utils/request.js) 是基于 axios 的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。 它封装了全局 request拦截器、response拦截器、统一的错误处理、统一做了超时处理、baseURL设置等。 </div> ### [#](#请求示例) 请求示例 <div class="language-js line-numbers-mode"> // api/system/user.js import request from '@/utils/request' // 查询用户列表 export function listUser(query) { return request({ url: '/system/user/list', method: 'get', params: query }) } // views/system/user/index.vue import { listUser } from "@/api/system/user"; export default { data() { userList: null, loading: true }, methods: { getList() { this.loading = true listUser().then(response => { this.userList = response.rows this.loading = false }) } } } </div> <div class="custom-block tip"> 提示 如果有不同的`baseURL`,直接通过覆盖的方式,让它具有不同的`baseURL`。 <div class="language-js line-numbers-mode"> export function listUser(query) { return request({ url: '/system/user/list', method: 'get', params: query, baseURL: process.env.BASE_API }) } </div> </div> ## [#](#引入依赖) 引入依赖 除了 element-ui 组件以及脚手架内置的业务组件,有时我们还需要引入其他外部组件,这里以引入 [vue-count-to<span><span class="sr-only">(opens new window)</span></span>](https://github.com/PanJiaChen/vue-countTo) 为例进行介绍。 在终端输入下面的命令完成安装: <div class="language-bash line-numbers-mode"> $ npm install vue-count-to --save </div> > 加上 `--save` 参数会自动添加依赖到 package.json 中去。 ## [#](#路由使用) 路由使用 框架的核心是通过路由自动生成对应导航,所以除了路由的基本配置,还需要了解框架提供了哪些配置项。 ### [#](#路由配置) 路由配置 <div class="language-js line-numbers-mode"> // 当设置 true 的时候该路由不会在侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 hidden: true // (默认 false) //当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 redirect: 'noRedirect' // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 // 若你想不管路由下面的 children 声明的个数都显示你的根路由 // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 alwaysShow: true name: 'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 meta: { title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 icon: 'svg-name' // 设置该路由的图标,支持 svg-class,也支持 el-icon-x element-ui 的 icon noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false) breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示(默认 true) affix: true // 如果设置为true,它则会固定在tags-view中(默认 false) // 当路由设置了该属性,则会高亮相对应的侧边栏。 // 这在某些场景非常有用,比如:一个文章的列表页路由为:/article/list // 点击文章进入文章详情页,这时候路由为/article/1,但你想在侧边栏高亮文章列表的路由,就可以进行如下设置 activeMenu: '/article/list' } </div> **普通示例** <div class="language-json line-numbers-mode"> { path: '/system/test', component: Layout, redirect: 'noRedirect', hidden: false, alwaysShow: true, meta: { title: '系统管理', icon : "system" }, children: [{ path: 'index', component: (resolve) => require(['@/views/index'], resolve), name: 'Test', meta: { title: '测试管理', icon: 'user' } }] } </div> **外链示例** <div class="language-json line-numbers-mode"> { path: 'http://ruoyi.vip', meta: { title: '若依官网', icon : "guide" } } </div> ### [#](#静态路由) 静态路由 代表那些不需要动态判断权限的路由,如登录页、404、等通用页面,在[@/router/index.js<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/blob/master/ruoyi-ui/src/router/index.js)配置对应的公共路由。 ### [#](#动态路由) 动态路由 代表那些需要根据用户动态判断权限并通过`addRoutes`动态添加的页面,在[@/store/modules/permission.js<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/blob/master/ruoyi-ui/src/store/modules/permission.js)加载后端接口路由配置。 <div class="custom-block tip"> 提示 * 动态路由可以在系统管理-菜单管理进行新增和修改操作,前端加载会自动请求接口获取菜单信息并转换成前端对应的路由。 * 动态路由在生产环境下会默认使用路由懒加载,实现方式参考`loadView`方法的判断。 </div> ### [#](#常用方法) 常用方法 想要跳转到不同的页面,使用`router.push`方法 <div class="language-js line-numbers-mode"> this.$router.push({ path: "/system/user" }); </div> 跳转页面并设置请求参数,使用`query`属性 <div class="language-js line-numbers-mode"> this.$router.push({ path: "/system/user", query: {id: "1", name: "若依"} }); </div> 更多使用可以参考[vue-router<span><span class="sr-only">(opens new window)</span></span>](https://router.vuejs.org/zh)官方文档。 ## [#](#组件使用) 组件使用 vue 注册组件的两种方式 ### [#](#局部注册) 局部注册 在对应页使用`components`注册组件。 <div class="language-html line-numbers-mode"> <template> <count-to :startVal='startVal' :endVal='endVal' :duration='3000'></count-to> </template> <script> import countTo from 'vue-count-to'; export default { components: { countTo }, data () { return { startVal: 0, endVal: 2020 } } } </script> </div> ### [#](#全局注册) 全局注册 在 [@/main.js<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/blob/master/ruoyi-ui/src/main.js) 文件下注册组件。 <div class="language-js line-numbers-mode"> import countTo from 'vue-count-to' Vue.component('countTo', countTo) </div> <div class="language-html line-numbers-mode"> <template> <count-to :startVal='startVal' :endVal='endVal' :duration='3000'></count-to> </template> </div> ### [#](#创建使用) 创建使用 可以通过创建一个后缀名为`vue`的文件,在通过`components`进行注册即可。 **例如定义一个`a.vue`文件** <div class="language-vue line-numbers-mode"> <!-- 子组件 --> <template> <div>这是a组件</div> </template> </div> **在其他组件中导入并注册** <div class="language-vue line-numbers-mode"> <!-- 父组件 --> <template> <div style="text-align: center; font-size: 20px"> 测试页面 <testa></testa> </div> </template> <script> import a from "./a"; export default { components: { testa: a } }; </script> </div> ### [#](#组件通信) 组件通信 **通过`props`来接收外界传递到组件内部的值** <div class="language-vue line-numbers-mode"> <!-- 父组件 --> <template> <div style="text-align: center; font-size: 20px"> 测试页面 <testa :name="name"></testa> </div> </template> <script> import a from "./a"; export default { components: { testa: a }, data() { return { name: "若依" }; }, }; </script> <!-- 子组件 --> <template> <div>这是a组件 name:{{ name }}</div> </template> <script> export default { props: { name: { type: String, default: "" }, } }; </script> </div> **使用`$emit`监听子组件触发的事件** <div class="language-vue line-numbers-mode"> <!-- 父组件 --> <template> <div style="text-align: center; font-size: 20px"> 测试页面 <testa :name="name" @ok="ok"></testa> 子组件传来的值 : {{ message }} </div> </template> <script> import a from "./a"; export default { components: { testa: a }, data() { return { name: "若依", message: "" }; }, methods: { ok(message) { this.message = message; }, }, }; </script> <!-- 子组件 --> <template> <div> 这是a组件 name:{{ name }} <button @click="click">发送</button> </div> </template> <script> export default { props: { name: { type: String, default: "" }, }, data() { return { message: "我是来自子组件的消息" }; }, methods: { click() { this.$emit("ok", this.message); }, }, }; </script> </div> ## [#](#权限使用) 权限使用 封装了一个指令权限,能简单快速的实现按钮级别的权限判断。[v-permission<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui/src/directive/permission) **使用权限字符串 v-hasPermi** <div class="language-html line-numbers-mode"> // 单个 <el-button v-hasPermi="['system:user:add']">存在权限字符串才能看到</el-button> // 多个 <el-button v-hasPermi="['system:user:add', 'system:user:edit']">包含权限字符串才能看到</el-button> </div> **使用角色字符串 v-hasRole** <div class="language-html line-numbers-mode"> // 单个 <el-button v-hasRole="['admin']">管理员才能看到</el-button> // 多个 <el-button v-hasRole="['role1', 'role2']">包含角色才能看到</el-button> </div> <div class="custom-block tip"> 提示 在某些情况下,它是不适合使用v-hasPermi,如元素标签组件,只能通过手动设置v-if。 可以使用全局权限判断函数,用法和指令 v-hasPermi 类似。 </div> <div class="language-html line-numbers-mode"> <template> <el-tabs> <el-tab-pane v-if="checkPermi(['system:user:add'])" label="用户管理" name="user">用户管理</el-tab-pane> <el-tab-pane v-if="checkPermi(['system:user:add', 'system:user:edit'])" label="参数管理" name="menu">参数管理</el-tab-pane> <el-tab-pane v-if="checkRole(['admin'])" label="角色管理" name="role">角色管理</el-tab-pane> <el-tab-pane v-if="checkRole(['admin','common'])" label="定时任务" name="job">定时任务</el-tab-pane> </el-tabs> </template> <script> import { checkPermi, checkRole } from "@/utils/permission"; // 权限判断函数 export default{ methods: { checkPermi, checkRole } } </script> </div> <div class="custom-block warning"> 前端有了鉴权后端还需要鉴权吗? 前端的鉴权只是一个辅助功能,对于专业人员这些限制都是可以轻松绕过的,为保证服务器安全,无论前端是否进行了权限校验,后端接口都需要对会话请求再次进行权限校验! </div> ## [#](#多级目录) 多级目录 如果你的路由是多级目录,有三级路由嵌套的情况下,还需要手动在二级目录的根文件下添加一个 `<router-view>`。 如:[@/views/system/log/index.vue<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/blob/master/ruoyi-ui/src/views/system/log/index.vue),原则上有多少级路由嵌套就需要多少个`<router-view>`。 ![](http://ruoyi.vip/docs/djml.png) <div class="custom-block tip"> 提示 最新版本多级目录已经支持自动配置组件,无需添加`<router-view>`。 </div> ## [#](#页签缓存) 页签缓存 由于目前 `keep-alive` 和 `router-view` 是强耦合的,而且查看文档和源码不难发现 `keep-alive` 的 [include<span><span class="sr-only">(opens new window)</span></span>](https://cn.vuejs.org/v2/api/#keep-alive) 默认是优先匹配组件的 **name** ,所以在编写路由 router 和路由对应的 view component 的时候一定要确保 两者的 name 是完全一致的。(切记 name 命名时候尽量保证唯一性 切记不要和某些组件的命名重复了,不然会递归引用最后内存溢出等问题) **DEMO:** <div class="language-js line-numbers-mode"> //router 路由声明 { path: 'config', component: ()=>import('@/views/system/config/index'), name: 'Config', meta: { title: '参数设置', icon: 'edit' } } </div> <div class="language-js line-numbers-mode"> //路由对应的view system/config/index export default { name: 'Config' } </div> 一定要保证两者的名字相同,切记写重或者写错。默认如果不写 name 就不会被缓存,详情见[issue<span><span class="sr-only">(opens new window)</span></span>](https://github.com/vuejs/vue/issues/6938#issuecomment-345728620)。 <div class="custom-block tip"> 提示 在系统管理-菜单管理-可以配置菜单页签是否缓存,默认为缓存 </div> ## [#](#使用图标) 使用图标 全局 Svg Icon 图标组件。 默认在 [@/icons/index.js<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/blob/master/ruoyi-ui/src/assets/icons/index.js) 中注册到全局中,可以在项目中任意地方使用。所以图标均可在 [@/icons/svg<span><span class="sr-only">(opens new window)</span></span>](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui/src/assets/icons/svg)。可自行添加或者删除图标,所以图标都会被自动导入,无需手动操作。 ### [#](#使用方式) 使用方式 <div class="language-html line-numbers-mode"> <!-- icon-class 为 icon 的名字; class-name 为 icon 自定义 class--> <svg-icon icon-class="password" class-name='custom-class' /> </div> ### [#](#改变颜色) 改变颜色 `svg-icon` 默认会读取其父级的 color `fill: currentColor;` 你可以改变父级的`color`或者直接改变`fill`的颜色即可。 <div class="custom-block tip"> 提示 如果你是从 [iconfont<span><span class="sr-only">(opens new window)</span></span>](https://www.iconfont.cn/)下载的图标,记得使用如 Sketch 等工具规范一下图标的大小问题,不然可能会造成项目中的图标大小尺寸不统一的问题。 本项目中使用的图标都是 128*128 大小规格的。 </div> ## [#](#使用字典) 使用字典 字典管理是用来维护数据类型的数据,如下拉框、单选按钮、复选框、树选择的数据,方便系统管理员维护。主要功能包括:字典分类管理、字典数据管理 **大于`3.7.0`版本使用如下方法** 1、main.js中引入全局变量和方法(已有) <div class="language-js line-numbers-mode"> import DictData from '@/components/DictData' DictData.install() </div> 2、加载数据字典,可以是多个。 <div class="language-js line-numbers-mode"> export default { dicts: ['字典类型'], ... ... </div> 3、读取数据字典 <div class="language-js line-numbers-mode"> <el-option v-for="dict in dict.type.字典类型" :key="dict.value" :label="dict.label" :value="dict.value" /> </div> 4、翻译数据字典 <div class="language-vue line-numbers-mode"> // 字典标签组件翻译 <el-table-column label="名称" align="center" prop="name"> <template slot-scope="scope"> <dict-tag :options="dict.type.字典类型" :value="scope.row.name"/> </template> </el-table-column> // 自定义方法翻译 {{ xxxxFormat(form) }} xxxxFormat(row, column) { return this.selectDictLabel(this.dict.type.字典类型, row.name); }, </div> **小于`3.7.0`版本使用如下方法** 1、main.js中引入全局变量和方法(已有) <div class="language-js line-numbers-mode"> import { getDicts } from "@/api/system/dict/data"; Vue.prototype.getDicts = getDicts </div> 2、加载数据字典 <div class="language-js line-numbers-mode"> export default { data() { return { xxxxxOptions: [], ..... ... created() { this.getDicts("字典类型").then(response => { this.xxxxxOptions = response.data; }); }, </div> 3、读取数据字典 <div class="language-js line-numbers-mode"> <el-option v-for="dict in xxxxxOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" /> </div> 4、翻译数据字典 <div class="language-vue line-numbers-mode"> // 字典标签组件翻译 <el-table-column label="名称" align="center" prop="name"> <template slot-scope="scope"> <dict-tag :options="xxxxxOptions" :value="scope.row.name"/> </template> </el-table-column> // 自定义方法翻译 {{ xxxxFormat(form) }} xxxxFormat(row, column) { return this.selectDictLabel(this.xxxxxOptions, row.name); }, </div> ## [#](#使用参数) 使用参数 参数设置是提供开发人员、实施人员的动态系统配置参数,不需要去频繁修改后台配置文件,也无需重启服务器即可生效。 1、main.js中引入全局变量和方法(已有) <div class="language-js line-numbers-mode"> import { getConfigKey } from "@/api/system/config"; Vue.prototype.getConfigKey = getConfigKey </div> 2、页面使用参数 <div class="language-js line-numbers-mode"> this.getConfigKey("参数键名").then(response => { this.xxxxx = response.msg; }); </div> ## [#](#异常处理) 异常处理 `@/utils/request.js` 是基于 `axios` 的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。它封装了全局 `request拦截器`、`response拦截器`、`统一的错误处理`、`统一做了超时处理`、`baseURL设置等`。 如果有自定义错误码可以在`errorCode.js`中设置对应`key` `value`值。 <div class="language-js line-numbers-mode"> import axios from 'axios' import { Notification, MessageBox, Message } from 'element-ui' import store from '@/store' import { getToken } from '@/utils/auth' import errorCode from '@/utils/errorCode' import { tansParams } from "@/utils/ruoyi"; axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' // 创建axios实例 const service = axios.create({ // axios中请求配置有baseURL选项,表示请求URL公共部分 baseURL: process.env.VUE_APP_BASE_API, // 超时 timeout: 10000 }) // request拦截器 service.interceptors.request.use(config => { // 是否需要设置 token const isToken = (config.headers || {}).isToken === false if (getToken() && !isToken) { config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 } return config }, error => { console.log(error) Promise.reject(error) }) // 响应拦截器 service.interceptors.response.use(res => { // 未设置状态码则默认成功状态 const code = res.data.code || 200; // 获取错误信息 const msg = errorCode[code] || res.data.msg || errorCode['default'] if (code === 401) { MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' } ).then(() => { store.dispatch('LogOut').then(() => { location.href = '/index'; }) }) } else if (code === 500) { Message({ message: msg, type: 'error' }) return Promise.reject(new Error(msg)) } else if (code !== 200) { Notification.error({ title: msg }) return Promise.reject('error') } else { return res.data } }, error => { console.log('err' + error) let { message } = error; if (message == "Network Error") { message = "后端接口连接异常"; } else if (message.includes("timeout")) { message = "系统接口请求超时"; } else if (message.includes("Request failed with status code")) { message = "系统接口" + message.substr(message.length - 3) + "异常"; } Message({ message: message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) // 通用下载方法 export function download(url, params, filename) { return service.post(url, params, { transformRequest: [(params) => { return tansParams(params) }], responseType: 'blob' }).then((data) => { const content = data const blob = new Blob([content]) if ('download' in document.createElement('a')) { const elink = document.createElement('a') elink.download = filename elink.style.display = 'none' elink.href = URL.createObjectURL(blob) document.body.appendChild(elink) elink.click() URL.revokeObjectURL(elink.href) document.body.removeChild(elink) } else { navigator.msSaveBlob(blob, filename) } }).catch((r) => { console.error(r) }) } export default service </div> <div class="custom-block tip"> 提示 如果有些不需要传递token的请求,可以设置`headers`中的属性`isToken`为`false` <div class="language-js line-numbers-mode"> export function login(username, password, code, uuid) { return request({ url: 'xxxx', headers: { isToken: false, // 可以自定义 Authorization // 'Authorization': 'Basic d2ViOg==' }, method: 'get' }) } </div> </div> ## [#](#应用路径) 应用路径 有些特殊情况需要部署到子路径下,例如:`https://www.ruoyi.vip/admin`,可以按照下面流程修改。 1、修改`vue.config.js`中的`publicPath`属性 <div class="language-js line-numbers-mode"> publicPath: process.env.NODE_ENV === "production" ? "/admin/" : "/admin/", </div> 2、修改`router/index.js`,添加一行`base`属性 <div class="language-js line-numbers-mode"> export default new Router({ base: "/admin", mode: 'history', // 去掉url中的# scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }) </div> 3、`/index`路由添加获取子路径`/admin` 修改`layout/components/Navbar.vue`中的`location.href` <div class="language-js line-numbers-mode"> location.href = '/admin/index'; </div> 修改`utils/request.js`中的`location.href` <div class="language-js line-numbers-mode"> location.href = '/admin/index'; </div> 4、修改`nginx`配置 <div class="language- line-numbers-mode"> location /admin { alias /home/ruoyi/projects/ruoyi-ui; try_files $uri $uri/ /admin/index.html; index index.html index.htm; } </div> 打开浏览器,输入:`https://www.ruoyi.vip/admin` 能正常访问和刷新表示成功。 </div>