diff --git a/ruoyi-ui/src/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue
index 258a9474..504d32a2 100644
--- a/ruoyi-ui/src/layout/components/Navbar.vue
+++ b/ruoyi-ui/src/layout/components/Navbar.vue
@@ -1,208 +1,210 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index 958ca4b8..2479aa0f 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -1,183 +1,186 @@
-import Vue from 'vue'
-import Router from 'vue-router'
-
-Vue.use(Router)
-
-/* Layout */
-import Layout from '@/layout'
-
-/**
- * Note: 路由配置项
- *
- * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
- * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
- * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
- * // 若你想不管路由下面的 children 声明的个数都显示你的根路由
- * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
- * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
- * name:'router-name' // 设定路由的名字,一定要填写不然使用时会出现各种问题
- * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
- * roles: ['admin', 'common'] // 访问路由的角色权限
- * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
- * meta : {
- noCache: true // 如果设置为true,则不会被 缓存(默认 false)
- title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
- icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg
- breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
- activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
- }
- */
-
-// 公共路由
-export const constantRoutes = [
- {
- path: '/redirect',
- component: Layout,
- hidden: true,
- children: [
- {
- path: '/redirect/:path(.*)',
- component: () => import('@/views/redirect')
- }
- ]
- },
- {
- path: '/login',
- component: () => import('@/views/login'),
- hidden: true
- },
- {
- path: '/register',
- component: () => import('@/views/register'),
- hidden: true
- },
- {
- path: '/404',
- component: () => import('@/views/error/404'),
- hidden: true
- },
- {
- path: '/401',
- component: () => import('@/views/error/401'),
- hidden: true
- },
- {
- path: '',
- component: Layout,
- redirect: 'index',
- children: [
- {
- path: 'index',
- component: () => import('@/views/index'),
- name: 'Index',
- meta: { title: '首页', icon: 'dashboard', affix: true }
- }
- ]
- },
- {
- path: '/user',
- component: Layout,
- hidden: true,
- redirect: 'noredirect',
- children: [
- {
- path: 'profile',
- component: () => import('@/views/system/user/profile/index'),
- name: 'Profile',
- meta: { title: '个人中心', icon: 'user' }
- }
- ]
- }
-]
-
-// 动态路由,基于用户权限动态去加载
-export const dynamicRoutes = [
- {
- path: '/system/user-auth',
- component: Layout,
- hidden: true,
- permissions: ['system:user:edit'],
- children: [
- {
- path: 'role/:userId(\\d+)',
- component: () => import('@/views/system/user/authRole'),
- name: 'AuthRole',
- meta: { title: '分配角色', activeMenu: '/system/user' }
- }
- ]
- },
- {
- path: '/system/role-auth',
- component: Layout,
- hidden: true,
- permissions: ['system:role:edit'],
- children: [
- {
- path: 'user/:roleId(\\d+)',
- component: () => import('@/views/system/role/authUser'),
- name: 'AuthUser',
- meta: { title: '分配用户', activeMenu: '/system/role' }
- }
- ]
- },
- {
- path: '/system/dict-data',
- component: Layout,
- hidden: true,
- permissions: ['system:dict:list'],
- children: [
- {
- path: 'index/:dictId(\\d+)',
- component: () => import('@/views/system/dict/data'),
- name: 'Data',
- meta: { title: '字典数据', activeMenu: '/system/dict' }
- }
- ]
- },
- {
- path: '/monitor/job-log',
- component: Layout,
- hidden: true,
- permissions: ['monitor:job:list'],
- children: [
- {
- path: 'index/:jobId(\\d+)',
- component: () => import('@/views/monitor/job/log'),
- name: 'JobLog',
- meta: { title: '调度日志', activeMenu: '/monitor/job' }
- }
- ]
- },
- {
- path: '/tool/gen-edit',
- component: Layout,
- hidden: true,
- permissions: ['tool:gen:edit'],
- children: [
- {
- path: 'index/:tableId(\\d+)',
- component: () => import('@/views/tool/gen/editTable'),
- name: 'GenEdit',
- meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
- }
- ]
- }
-]
-
-// 防止连续点击多次路由报错
-let routerPush = Router.prototype.push
-let routerReplace = Router.prototype.replace
-// push
-Router.prototype.push = function push(location) {
- return routerPush.call(this, location).catch(err => err)
-}
-// replace
-Router.prototype.replace = function push(location) {
- return routerReplace.call(this, location).catch(err => err)
-}
-
-export default new Router({
- mode: 'history', // 去掉url中的#
- scrollBehavior: () => ({ y: 0 }),
- routes: constantRoutes
-})
+import Vue from 'vue'
+import Router from 'vue-router'
+
+Vue.use(Router)
+
+/* Layout */
+import Layout from '@/layout'
+
+/**
+ * Note: 路由配置项
+ *
+ * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
+ * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
+ * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
+ * // 若你想不管路由下面的 children 声明的个数都显示你的根路由
+ * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
+ * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
+ * name:'router-name' // 设定路由的名字,一定要填写不然使用时会出现各种问题
+ * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
+ * roles: ['admin', 'common'] // 访问路由的角色权限
+ * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
+ * meta : {
+ noCache: true // 如果设置为true,则不会被 缓存(默认 false)
+ title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
+ icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg
+ breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
+ activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
+ }
+ */
+
+// 公共路由
+export const constantRoutes = [
+ {
+ path: '/redirect',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: '/redirect/:path(.*)',
+ component: () => import('@/views/redirect')
+ }
+ ]
+ },
+ {
+ path: '/login',
+ component: () => import('@/views/login'),
+ hidden: true
+ },
+ {
+ path: '/register',
+ component: () => import('@/views/register'),
+ hidden: true
+ },
+ {
+ path: '/404',
+ component: () => import('@/views/error/404'),
+ hidden: true
+ },
+ {
+ path: '/401',
+ component: () => import('@/views/error/401'),
+ hidden: true
+ },
+ {
+ path: '',
+ component: Layout,
+ redirect: 'index',
+ children: [
+ {
+ path: 'index',
+ component: () => import('@/views/index'),
+ name: 'Index',
+ meta: { title: '首页', icon: 'dashboard', affix: true }
+ }
+ ]
+ },
+ {
+ path: '/user',
+ component: Layout,
+ hidden: true,
+ redirect: 'noredirect',
+ children: [
+ {
+ path: 'profile',
+ component: () => import('@/views/system/user/profile/index'),
+ name: 'Profile',
+ meta: { title: '个人中心', icon: 'user' }
+ }
+ ]
+ }
+]
+
+// 动态路由,基于用户权限动态去加载
+export const dynamicRoutes = [
+ {
+ path: '/system/user-auth',
+ component: Layout,
+ hidden: true,
+ permissions: ['system:user:edit'],
+ children: [
+ {
+ path: 'role/:userId(\\d+)',
+ component: () => import('@/views/system/user/authRole'),
+ name: 'AuthRole',
+ meta: { title: '分配角色', activeMenu: '/system/user' }
+ }
+ ]
+ },
+ {
+ path: '/system/role-auth',
+ component: Layout,
+ hidden: true,
+ permissions: ['system:role:edit'],
+ children: [
+ {
+ path: 'user/:roleId(\\d+)',
+ component: () => import('@/views/system/role/authUser'),
+ name: 'AuthUser',
+ meta: { title: '分配用户', activeMenu: '/system/role' }
+ }
+ ]
+ },
+ {
+ path: '/system/dict-data',
+ component: Layout,
+ hidden: true,
+ permissions: ['system:dict:list'],
+ children: [
+ {
+ path: 'index/:dictId(\\d+)',
+ component: () => import('@/views/system/dict/data'),
+ name: 'Data',
+ meta: { title: '字典数据', activeMenu: '/system/dict' }
+ }
+ ]
+ },
+ {
+ path: '/monitor/job-log',
+ component: Layout,
+ hidden: true,
+ permissions: ['monitor:job:list'],
+ children: [
+ {
+ path: 'index/:jobId(\\d+)',
+ component: () => import('@/views/monitor/job/log'),
+ name: 'JobLog',
+ meta: { title: '调度日志', activeMenu: '/monitor/job' }
+ }
+ ]
+ },
+ {
+ path: '/tool/gen-edit',
+ component: Layout,
+ hidden: true,
+ permissions: ['tool:gen:edit'],
+ children: [
+ {
+ path: 'index/:tableId(\\d+)',
+ component: () => import('@/views/tool/gen/editTable'),
+ name: 'GenEdit',
+ meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
+ }
+ ]
+ }
+]
+
+// 防止连续点击多次路由报错
+let routerPush = Router.prototype.push
+let routerReplace = Router.prototype.replace
+// push
+Router.prototype.push = function push(location) {
+ return routerPush.call(this, location).catch(err => err)
+}
+// replace
+Router.prototype.replace = function push(location) {
+ return routerReplace.call(this, location).catch(err => err)
+}
+
+export default new Router({
+ mode: 'history', // 去掉url中的#
+ // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
+ // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
+ base: process.env.NODE_ENV === "production" ? "/" : "/",
+ scrollBehavior: () => ({ y: 0 }),
+ routes: constantRoutes
+})
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
index e75828f8..ffedc78a 100644
--- a/ruoyi-ui/src/utils/request.js
+++ b/ruoyi-ui/src/utils/request.js
@@ -1,152 +1,156 @@
-import axios from 'axios'
-import { Notification, MessageBox, Message, Loading } from 'element-ui'
-import store from '@/store'
-import { getToken } from '@/utils/auth'
-import errorCode from '@/utils/errorCode'
-import { tansParams, blobValidate } from "@/utils/ruoyi"
-import cache from '@/plugins/cache'
-import { saveAs } from 'file-saver'
-
-let downloadLoadingInstance
-// 是否显示重新登录
-export let isRelogin = { show: false }
-
-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
- // 是否需要防止数据重复提交
- const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
- if (getToken() && !isToken) {
- config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
- }
- // get请求映射params参数
- if (config.method === 'get' && config.params) {
- let url = config.url + '?' + tansParams(config.params)
- url = url.slice(0, -1)
- config.params = {}
- config.url = url
- }
- if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
- const requestObj = {
- url: config.url,
- data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
- time: new Date().getTime()
- }
- const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
- const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
- if (requestSize >= limitSize) {
- console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
- return config
- }
- const sessionObj = cache.session.getJSON('sessionObj')
- if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
- cache.session.setJSON('sessionObj', requestObj)
- } else {
- const s_url = sessionObj.url // 请求地址
- const s_data = sessionObj.data // 请求数据
- const s_time = sessionObj.time // 请求时间
- const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
- if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
- const message = '数据正在处理,请勿重复提交'
- console.warn(`[${s_url}]: ` + message)
- return Promise.reject(new Error(message))
- } else {
- cache.session.setJSON('sessionObj', requestObj)
- }
- }
- }
- 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 (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
- return res.data
- }
- if (code === 401) {
- if (!isRelogin.show) {
- isRelogin.show = true
- MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
- isRelogin.show = false
- store.dispatch('LogOut').then(() => {
- location.href = '/index'
- })
- }).catch(() => {
- isRelogin.show = false
- })
- }
- return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
- } else if (code === 500) {
- Message({ message: msg, type: 'error' })
- return Promise.reject(new Error(msg))
- } else if (code === 601) {
- Message({ message: msg, type: 'warning' })
- return Promise.reject('error')
- } 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, config) {
- downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
- return service.post(url, params, {
- transformRequest: [(params) => { return tansParams(params) }],
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
- responseType: 'blob',
- ...config
- }).then(async (data) => {
- const isBlob = blobValidate(data)
- if (isBlob) {
- const blob = new Blob([data])
- saveAs(blob, filename)
- } else {
- const resText = await data.text()
- const rspObj = JSON.parse(resText)
- const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
- Message.error(errMsg)
- }
- downloadLoadingInstance.close()
- }).catch((r) => {
- console.error(r)
- Message.error('下载文件出现错误,请联系管理员!')
- downloadLoadingInstance.close()
- })
-}
-
-export default service
+import axios from 'axios'
+import { Notification, MessageBox, Message, Loading } from 'element-ui'
+import store from '@/store'
+import { getToken } from '@/utils/auth'
+import errorCode from '@/utils/errorCode'
+import { tansParams, blobValidate } from "@/utils/ruoyi"
+import cache from '@/plugins/cache'
+import { saveAs } from 'file-saver'
+
+// 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
+// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
+export const BASE_PATH = '/'
+
+let downloadLoadingInstance
+// 是否显示重新登录
+export let isRelogin = { show: false }
+
+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
+ // 是否需要防止数据重复提交
+ const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
+ if (getToken() && !isToken) {
+ config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
+ }
+ // get请求映射params参数
+ if (config.method === 'get' && config.params) {
+ let url = config.url + '?' + tansParams(config.params)
+ url = url.slice(0, -1)
+ config.params = {}
+ config.url = url
+ }
+ if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
+ const requestObj = {
+ url: config.url,
+ data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
+ time: new Date().getTime()
+ }
+ const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
+ const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
+ if (requestSize >= limitSize) {
+ console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
+ return config
+ }
+ const sessionObj = cache.session.getJSON('sessionObj')
+ if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
+ cache.session.setJSON('sessionObj', requestObj)
+ } else {
+ const s_url = sessionObj.url // 请求地址
+ const s_data = sessionObj.data // 请求数据
+ const s_time = sessionObj.time // 请求时间
+ const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
+ if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
+ const message = '数据正在处理,请勿重复提交'
+ console.warn(`[${s_url}]: ` + message)
+ return Promise.reject(new Error(message))
+ } else {
+ cache.session.setJSON('sessionObj', requestObj)
+ }
+ }
+ }
+ 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 (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+ return res.data
+ }
+ if (code === 401) {
+ if (!isRelogin.show) {
+ isRelogin.show = true
+ MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
+ isRelogin.show = false
+ store.dispatch('LogOut').then(() => {
+ location.href = '/index'
+ })
+ }).catch(() => {
+ isRelogin.show = false
+ })
+ }
+ return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
+ } else if (code === 500) {
+ Message({ message: msg, type: 'error' })
+ return Promise.reject(new Error(msg))
+ } else if (code === 601) {
+ Message({ message: msg, type: 'warning' })
+ return Promise.reject('error')
+ } 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, config) {
+ downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
+ return service.post(url, params, {
+ transformRequest: [(params) => { return tansParams(params) }],
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ responseType: 'blob',
+ ...config
+ }).then(async (data) => {
+ const isBlob = blobValidate(data)
+ if (isBlob) {
+ const blob = new Blob([data])
+ saveAs(blob, filename)
+ } else {
+ const resText = await data.text()
+ const rspObj = JSON.parse(resText)
+ const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+ Message.error(errMsg)
+ }
+ downloadLoadingInstance.close()
+ }).catch((r) => {
+ console.error(r)
+ Message.error('下载文件出现错误,请联系管理员!')
+ downloadLoadingInstance.close()
+ })
+}
+
+export default service