diff --git a/.env.development b/.env.development
index 53750c9..7edd98a 100644
--- a/.env.development
+++ b/.env.development
@@ -20,6 +20,8 @@ VITE_APP_PORT = 80
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
+VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
# 客户端id
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
diff --git a/.env.production b/.env.production
index c463542..0e3b9fc 100644
--- a/.env.production
+++ b/.env.production
@@ -23,6 +23,8 @@ VITE_APP_PORT = 80
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
+VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
# 客户端id
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
diff --git a/README.md b/README.md
index 6644daf..2742463 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,9 @@ npm install --registry=https://registry.npmmirror.com
# 启动服务
npm run dev
-# 构建生产环境 yarn build:prod
+# 构建生产环境
+npm run build:prod
+
# 前端访问地址 http://localhost:80
```
diff --git a/package.json b/package.json
index 13e0f92..6af6ba2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ruoyi-vue-plus",
- "version": "5.1.1",
+ "version": "5.1.2",
"description": "RuoYi-Vue-Plus多租户管理系统",
"author": "LionLi",
"license": "MIT",
diff --git a/src/components/DictTag/index.vue b/src/components/DictTag/index.vue
index 1057b3f..45b288b 100644
--- a/src/components/DictTag/index.vue
+++ b/src/components/DictTag/index.vue
@@ -2,7 +2,7 @@
-
{{ item.label + " " }}
@@ -11,7 +11,7 @@
:disable-transitions="true"
:key="item.value + ''"
:index="index"
- :type="item.elTagType === 'primary' ? '' : item.elTagType"
+ :type="(item.elTagType === 'primary' || item.elTagType === 'default')? '' : item.elTagType"
:class="item.elTagClass"
>
{{ item.label + " " }}
diff --git a/src/components/IconSelect/index.vue b/src/components/IconSelect/index.vue
index a275954..1cd0023 100644
--- a/src/components/IconSelect/index.vue
+++ b/src/components/IconSelect/index.vue
@@ -2,7 +2,7 @@
-
+
diff --git a/src/layout/components/Sidebar/SidebarItem.vue b/src/layout/components/Sidebar/SidebarItem.vue
index 204b19b..4459cdf 100644
--- a/src/layout/components/Sidebar/SidebarItem.vue
+++ b/src/layout/components/Sidebar/SidebarItem.vue
@@ -18,8 +18,8 @@
{
if (to.path === '/login') {
next({ path: '/' });
NProgress.done();
+ } else if (whiteList.indexOf(to.path) !== -1) {
+ next()
} else {
if (useUserStore().roles.length === 0) {
isRelogin.show = true;
diff --git a/src/router/index.ts b/src/router/index.ts
index 6c56cd3..271385c 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -139,7 +139,7 @@ export const dynamicRoutes: RouteOption[] = [
path: '/system/oss-config',
component: Layout,
hidden: true,
- permissions: ['system:oss:list'],
+ permissions: ['system:ossConfig:list'],
children: [
{
path: 'index',
diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts
index cd065d1..1c1c9a2 100644
--- a/src/store/modules/tagsView.ts
+++ b/src/store/modules/tagsView.ts
@@ -1,4 +1,4 @@
-import { TagView } from 'vue-router';
+import { TagView, RouteRecordNormalized } from 'vue-router';
export const useTagsViewStore = defineStore('tagsView', () => {
const visitedViews = ref([]);
@@ -35,7 +35,9 @@ export const useTagsViewStore = defineStore('tagsView', () => {
const delView = (view: TagView): Promise<{ visitedViews: TagView[]; cachedViews: string[] }> => {
return new Promise((resolve) => {
delVisitedView(view);
- delCachedView(view);
+ if (!isDynamicRoute(view)) {
+ delCachedView(view);
+ }
resolve({
visitedViews: [...visitedViews.value],
cachedViews: [...cachedViews.value]
@@ -177,6 +179,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
}
};
+ const isDynamicRoute = (view: any): boolean => {
+ // 检查匹配的路由记录中是否有动态段
+ return view.matched.some((m: RouteRecordNormalized) => m.path.includes(':'));
+ };
+
return {
visitedViews,
cachedViews,
diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts
index 2593d1a..7c02de0 100644
--- a/src/store/modules/user.ts
+++ b/src/store/modules/user.ts
@@ -63,6 +63,10 @@ export const useUserStore = defineStore('user', () => {
removeToken();
};
+ const setAvatar = (value: string) => {
+ avatar.value = value;
+ };
+
return {
userId,
token,
@@ -72,7 +76,8 @@ export const useUserStore = defineStore('user', () => {
permissions,
login,
getInfo,
- logout
+ logout,
+ setAvatar
};
});
diff --git a/src/types/env.d.ts b/src/types/env.d.ts
index 15fa03a..9560307 100644
--- a/src/types/env.d.ts
+++ b/src/types/env.d.ts
@@ -68,6 +68,7 @@ interface ImportMetaEnv {
VITE_APP_POWERJOB_ADMIN: string;
VITE_APP_ENV: string;
VITE_APP_RSA_PUBLIC_KEY: string;
+ VITE_APP_RSA_PRIVATE_KEY: string;
VITE_APP_CLIENT_ID: string;
VITE_APP_WEBSOCKET: string;
}
diff --git a/src/utils/crypto.ts b/src/utils/crypto.ts
index 133893e..8217146 100644
--- a/src/utils/crypto.ts
+++ b/src/utils/crypto.ts
@@ -30,6 +30,13 @@ export const encryptBase64 = (str: CryptoJS.lib.WordArray) => {
return CryptoJS.enc.Base64.stringify(str);
};
+/**
+ * 解密base64
+ */
+export const decryptBase64 = (str: string) => {
+ return CryptoJS.enc.Base64.parse(str);
+};
+
/**
* 使用密钥对数据进行加密
* @param message
@@ -43,3 +50,17 @@ export const encryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray)
});
return encrypted.toString();
};
+
+/**
+ * 使用密钥对数据进行解密
+ * @param message
+ * @param aesKey
+ * @returns {string}
+ */
+export const decryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray) => {
+ const decrypted = CryptoJS.AES.decrypt(message, aesKey, {
+ mode: CryptoJS.mode.ECB,
+ padding: CryptoJS.pad.Pkcs7
+ });
+ return decrypted.toString(CryptoJS.enc.Utf8);
+};
diff --git a/src/utils/jsencrypt.ts b/src/utils/jsencrypt.ts
index 98114b4..42de5a0 100644
--- a/src/utils/jsencrypt.ts
+++ b/src/utils/jsencrypt.ts
@@ -4,7 +4,7 @@ import JSEncrypt from 'jsencrypt';
const publicKey = import.meta.env.VITE_APP_RSA_PUBLIC_KEY;
// 前端不建议存放私钥 不建议解密数据 因为都是透明的意义不大
-const privateKey = '**********';
+const privateKey = import.meta.env.VITE_APP_RSA_PRIVATE_KEY;
// 加密
export const encrypt = (txt: string) => {
diff --git a/src/utils/request.ts b/src/utils/request.ts
index ed67713..a183ca6 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -8,9 +8,10 @@ import { errorCode } from '@/utils/errorCode';
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
import FileSaver from 'file-saver';
import { getLanguage } from '@/lang';
-import { encryptBase64, encryptWithAes, generateAesKey } from '@/utils/crypto';
-import { encrypt } from '@/utils/jsencrypt';
+import { encryptBase64, encryptWithAes, generateAesKey, decryptWithAes, decryptBase64 } from '@/utils/crypto';
+import { encrypt, decrypt } from '@/utils/jsencrypt';
+const encryptHeader = 'encrypt-key';
let downloadLoadingInstance: LoadingInstance;
// 是否显示重新登录
export const isRelogin = { show: false };
@@ -78,7 +79,7 @@ service.interceptors.request.use(
if (isEncrypt && (config.method === 'post' || config.method === 'put')) {
// 生成一个 AES 密钥
const aesKey = generateAesKey();
- config.headers['encrypt-key'] = encrypt(encryptBase64(aesKey));
+ config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
}
// FormData数据去请求头Content-Type
@@ -96,6 +97,20 @@ service.interceptors.request.use(
// 响应拦截器
service.interceptors.response.use(
(res: AxiosResponse) => {
+ // 加密后的 AES 秘钥
+ const keyStr = res.headers[encryptHeader];
+ // 加密
+ if (keyStr != null && keyStr != '') {
+ const data = res.data;
+ // 请求体 AES 解密
+ const base64Str = decrypt(keyStr);
+ // base64 解码 得到请求头的 AES 秘钥
+ const aesKey = decryptBase64(base64Str.toString());
+ // aesKey 解码 data
+ const decryptData = decryptWithAes(data, aesKey);
+ // 将结果 (得到的是 JSON 字符串) 转为 JSON
+ res.data = JSON.parse(decryptData);
+ }
// 未设置状态码则默认成功状态
const code = res.data.code || HttpStatus.SUCCESS;
// 获取错误信息
diff --git a/src/views/index.vue b/src/views/index.vue
index 7f658d8..12d764b 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -33,7 +33,7 @@
* 部署方式 Docker 容器编排 一键部署业务集群
* 国际化 SpringMessage Spring标准国际化方案
- 当前版本: v5.1.1
+ 当前版本: v5.1.2
¥免费开源
@@ -78,7 +78,7 @@
* 分布式监控 Prometheus、Grafana 全方位性能监控
* 其余与 Vue 版本一致
- 当前版本: v2.1.1
+ 当前版本: v2.1.2
¥免费开源
diff --git a/src/views/monitor/online/index.vue b/src/views/monitor/online/index.vue
index 1a25dc5..d105cd7 100644
--- a/src/views/monitor/online/index.vue
+++ b/src/views/monitor/online/index.vue
@@ -63,6 +63,8 @@