From 66bfff450cdd9258845b29946d70844a99389dcf Mon Sep 17 00:00:00 2001 From: "Michelle.Chung" <1242874891@qq.com> Date: Mon, 23 Oct 2023 20:32:38 +0800 Subject: [PATCH 01/15] =?UTF-8?q?update=20=E6=9B=B4=E6=96=B0=20logininfor/?= =?UTF-8?q?index,=20online/index=20=E5=AD=97=E6=AE=B5=E6=98=BE=E7=A4=BA=20?= =?UTF-8?q?(=E5=AE=A2=E6=88=B7=E7=AB=AF,=20=E8=AE=BE=E5=A4=87=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B)=20;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/monitor/logininfor/index.vue | 7 +++++++ src/views/monitor/online/index.vue | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/views/monitor/logininfor/index.vue b/src/views/monitor/logininfor/index.vue index 38ab1ad..067790e 100644 --- a/src/views/monitor/logininfor/index.vue +++ b/src/views/monitor/logininfor/index.vue @@ -76,6 +76,12 @@ sortable="custom" :sort-orders="['descending', 'ascending']" /> + + + + @@ -103,6 +109,7 @@ import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monit import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types"; const { proxy } = getCurrentInstance() as ComponentInternalInstance; +const { sys_device_type } = toRefs(proxy?.useDict("sys_device_type")); const { sys_common_status } = toRefs(proxy?.useDict("sys_common_status")); const loginInfoList = ref([]); diff --git a/src/views/monitor/online/index.vue b/src/views/monitor/online/index.vue index ddbd385..1a25dc5 100644 --- a/src/views/monitor/online/index.vue +++ b/src/views/monitor/online/index.vue @@ -29,6 +29,12 @@ + + + + @@ -59,6 +65,7 @@ import { forceLogout, list as initData } from "@/api/monitor/online"; import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types"; const { proxy } = getCurrentInstance() as ComponentInternalInstance; +const { sys_device_type } = toRefs(proxy?.useDict("sys_device_type")); const onlineList = ref([]); const loading = ref(true); From ccb2ecc5ee43f8b6f3b2e9efa3a5189bdce7c399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Wed, 25 Oct 2023 16:21:13 +0800 Subject: [PATCH 02/15] =?UTF-8?q?update=20=E6=9B=B4=E6=96=B0=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=9E=84=E5=BB=BA=E4=B8=8D=E8=83=BD=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/tool/build/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/tool/build/index.vue b/src/views/tool/build/index.vue index 45f5457..ef0c079 100644 --- a/src/views/tool/build/index.vue +++ b/src/views/tool/build/index.vue @@ -1,3 +1,3 @@ From 6ad0ed531652bf7fc3c92324ad2a48bf9ceb8950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Wed, 25 Oct 2023 23:05:32 +0800 Subject: [PATCH 03/15] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E5=A4=9A=E4=BD=99=E7=9A=84=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HeaderSearch/index.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/HeaderSearch/index.vue b/src/components/HeaderSearch/index.vue index 85c6ca0..b922c6c 100644 --- a/src/components/HeaderSearch/index.vue +++ b/src/components/HeaderSearch/index.vue @@ -88,7 +88,7 @@ const initFuse = (list: Router) => { } // Filter out the routes that can be displayed in the sidebar // And generate the internationalized title -const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = [], query: any = {}) => { +const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => { let res: Router = [] routes.forEach(r => { // skip hidden router @@ -114,7 +114,7 @@ const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: strin // recursive child routes if (r.children) { - const tempRoutes = generateRoutes(r.children, data.path, data.title, data.query); + const tempRoutes = generateRoutes(r.children, data.path, data.title); if (tempRoutes.length >= 1) { res = [...res, ...tempRoutes]; } From bf977fe00a88bad92a8d73648624cbf05b9218c4 Mon Sep 17 00:00:00 2001 From: bestrevens <201840026@qq.com> Date: Tue, 31 Oct 2023 08:54:22 +0000 Subject: [PATCH 04/15] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E5=88=97=E7=9A=84=E6=98=BE=E7=A4=BA=E4=B8=8E=E9=9A=90?= =?UTF-8?q?=E8=97=8F=E5=B0=8F=E7=BB=84=E4=BB=B6=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E5=88=97=E7=9A=84=E6=98=BE=E7=A4=BA=E4=B8=8E?= =?UTF-8?q?=E9=9A=90=E8=97=8F=E5=B0=8F=E7=BB=84=E4=BB=B6=EF=BC=8C=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=B0=8F=E7=BB=84=E4=BB=B6=E4=B9=8B=E9=97=B4=E8=B7=9D?= =?UTF-8?q?=E7=A6=BB=E9=97=B4=E9=9A=94=E4=B8=8D=E4=B8=80=E6=A0=B7=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: bestrevens <201840026@qq.com> --- src/components/RightToolbar/index.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/RightToolbar/index.vue b/src/components/RightToolbar/index.vue index 6f7b14f..6be382f 100644 --- a/src/components/RightToolbar/index.vue +++ b/src/components/RightToolbar/index.vue @@ -8,7 +8,7 @@ -
+
显示/隐藏列
{ line-height: 24px; text-align: center; } +.show-btn { + margin-left: 12px; +} From 631f338be23d0a91936bf7f048b38e91be4efaf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Wed, 1 Nov 2023 10:46:42 +0800 Subject: [PATCH 05/15] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=B3=A8=E5=86=8C=E7=BC=BA=E5=A4=B1=20clientid=20?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/login.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/login.ts b/src/api/login.ts index 7419fb3..100a5e9 100644 --- a/src/api/login.ts +++ b/src/api/login.ts @@ -29,6 +29,11 @@ export function login(data: LoginData): AxiosPromise { // 注册方法 export function register(data: any) { + const params = { + ...data, + clientId: clientId, + grantType: 'password' + }; return request({ url: '/auth/register', headers: { @@ -36,7 +41,7 @@ export function register(data: any) { isEncrypt: true }, method: 'post', - data: data + data: params }); } From a8a334b3c326610be70dd762978e8bf1a8766adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E4=B8=AA=E4=B8=89?= <2029364173@qq.com> Date: Thu, 2 Nov 2023 04:36:31 +0000 Subject: [PATCH 06/15] =?UTF-8?q?!50=20add=20=E6=96=B0=E5=A2=9E=20?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=8E=A5=E5=85=A5websocket=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E6=B6=88=E6=81=AF=20*=20=20add=20=E6=96=B0=E5=A2=9E=20?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=8E=A5=E5=85=A5websocket=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lang/en_US.ts | 1 + src/lang/zh_CN.ts | 1 + src/layout/components/Navbar.vue | 28 ++++++ src/layout/components/notice/index.vue | 134 +++++++++++++++++++++++++ src/store/modules/notice.ts | 42 ++++++++ src/utils/websocket.ts | 132 ++++++++++++++++++++++++ src/views/index.vue | 5 + vite.config.ts | 1 + 8 files changed, 344 insertions(+) create mode 100644 src/layout/components/notice/index.vue create mode 100644 src/store/modules/notice.ts create mode 100644 src/utils/websocket.ts diff --git a/src/lang/en_US.ts b/src/lang/en_US.ts index 59df4ba..034ea91 100644 --- a/src/lang/en_US.ts +++ b/src/lang/en_US.ts @@ -18,6 +18,7 @@ export default { language: 'Language', dashboard: 'Dashboard', document: 'Document', + message: 'Message', layoutSize: 'Layout Size', selectTenant: 'Select Tenant', layoutSetting: 'Layout Setting', diff --git a/src/lang/zh_CN.ts b/src/lang/zh_CN.ts index d778f7d..666a400 100644 --- a/src/lang/zh_CN.ts +++ b/src/lang/zh_CN.ts @@ -17,6 +17,7 @@ export default { language: '语言', dashboard: '首页', document: '项目文档', + message: '消息', layoutSize: '布局大小', selectTenant: '选择租户', layoutSetting: '布局设置', diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 3c0e45d..7818fd4 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -27,6 +27,21 @@
+ + +
+ + + + +
+
@@ -81,10 +96,14 @@ import { getTenantList } from "@/api/login"; import { dynamicClear, dynamicTenant } from "@/api/system/tenant"; import { ComponentInternalInstance } from "vue"; import { TenantVO } from "@/api/types"; +import notice from './notice/index.vue'; +import useNoticeStore from '@/store/modules/notice'; const appStore = useAppStore(); const userStore = useUserStore(); const settingsStore = useSettingsStore(); +const noticeStore = storeToRefs(useNoticeStore()); +const newNotice = ref(0); const { proxy } = getCurrentInstance() as ComponentInternalInstance; @@ -161,6 +180,11 @@ const handleCommand = (command: string) => { commandMap[command](); } } + +//用深度监听 消息 +watch(() => noticeStore.state.value.notices, (newVal, oldVal) => { + newNotice.value = newVal.filter((item: any) => !item.read).length; +}, { deep: true }); diff --git a/src/store/modules/notice.ts b/src/store/modules/notice.ts new file mode 100644 index 0000000..f3f8e5a --- /dev/null +++ b/src/store/modules/notice.ts @@ -0,0 +1,42 @@ +import { defineStore } from 'pinia'; + +interface NoticeItem { + title?: string; + read: boolean; + message: any; + time: string; +} + +export const useNoticeStore = defineStore('notice', () => { + const state = reactive({ + notices: [] as NoticeItem[] + }); + + const addNotice = (notice: NoticeItem) => { + state.notices.push(notice); + }; + + const removeNotice = (notice: NoticeItem) => { + state.notices.splice(state.notices.indexOf(notice), 1); + }; + + //实现全部已读 + const readAll = () => { + state.notices.forEach((item) => { + item.read = true; + }); + }; + + const clearNotice = () => { + state.notices = []; + }; + return { + state, + addNotice, + removeNotice, + readAll, + clearNotice + }; +}); + +export default useNoticeStore; diff --git a/src/utils/websocket.ts b/src/utils/websocket.ts new file mode 100644 index 0000000..90e86bf --- /dev/null +++ b/src/utils/websocket.ts @@ -0,0 +1,132 @@ +/** + * @module initWebSocket 初始化 + * @module websocketonopen 连接成功 + * @module websocketonerror 连接失败 + * @module websocketclose 断开连接 + * @module resetHeart 重置心跳 + * @module sendSocketHeart 心跳发送 + * @module reconnect 重连 + * @module sendMsg 发送数据 + * @module websocketonmessage 接收数据 + * @module test 测试收到消息传递 + * @description socket 通信 + * @param {any} url socket地址 + * @param {any} websocket websocket 实例 + * @param {any} heartTime 心跳定时器实例 + * @param {number} socketHeart 心跳次数 + * @param {number} HeartTimeOut 心跳超时时间 + * @param {number} socketError 错误次数 + */ + +import { getToken } from '@/utils/auth'; +import useNoticeStore from '@/store/modules/notice'; + +const { addNotice } = useNoticeStore(); + +let socketUrl: any = ''; // socket地址 +let websocket: any = null; // websocket 实例 +let heartTime: any = null; // 心跳定时器实例 +let socketHeart = 0 as number; // 心跳次数 +const HeartTimeOut = 10000; // 心跳超时时间 10000 = 10s +let socketError = 0 as number; // 错误次数 + +// 初始化socket +export const initWebSocket = (url: any) => { + socketUrl = url; + // 初始化 websocket + websocket = new WebSocket(url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID); + websocketonopen(); + websocketonmessage(); + websocketonerror(); + websocketclose(); + sendSocketHeart(); + return websocket; +}; + +// socket 连接成功 +export const websocketonopen = () => { + websocket.onopen = function () { + console.log('连接 websocket 成功'); + resetHeart(); + }; +}; + +// socket 连接失败 +export const websocketonerror = () => { + websocket.onerror = function (e: any) { + console.log('连接 websocket 失败', e); + }; +}; + +// socket 断开链接 +export const websocketclose = () => { + websocket.onclose = function (e: any) { + console.log('断开连接', e); + }; +}; + +// socket 重置心跳 +export const resetHeart = () => { + socketHeart = 0; + socketError = 0; + clearInterval(heartTime); + sendSocketHeart(); +}; + +// socket心跳发送 +export const sendSocketHeart = () => { + heartTime = setInterval(() => { + // 如果连接正常则发送心跳 + if (websocket.readyState == 1) { + // if (socketHeart <= 30) { + websocket.send( + JSON.stringify({ + type: 'ping' + }) + ); + socketHeart = socketHeart + 1; + } else { + // 重连 + reconnect(); + } + }, HeartTimeOut); +}; + +// socket重连 +export const reconnect = () => { + if (socketError <= 2) { + clearInterval(heartTime); + initWebSocket(socketUrl); + socketError = socketError + 1; + // eslint-disable-next-line prettier/prettier + console.log('socket重连', socketError); + } else { + // eslint-disable-next-line prettier/prettier + console.log('重试次数已用完'); + clearInterval(heartTime); + } +}; + +// socket 发送数据 +export const sendMsg = (data: any) => { + websocket.send(data); +}; + +// socket 接收数据 +export const websocketonmessage = () => { + websocket.onmessage = function (e: any) { + const msg = JSON.parse(e.data) as any; + if (msg.type === 'heartbeat') { + resetHeart(); + } + if (msg.type === 'ping') { + return; + } + addNotice({ + message: msg, + read: false, + time: new Date().toLocaleString() + }); + return msg; + }; +}; diff --git a/src/views/index.vue b/src/views/index.vue index 438c1af..40c88a8 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -96,6 +96,11 @@ From 0a8c33c3cb2265d19520adc89402a62ae6fea4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 10 Nov 2023 15:59:09 +0800 Subject: [PATCH 13/15] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20=E4=BA=94?= =?UTF-8?q?=E7=BA=A7=E8=B7=AF=E7=94=B1=E7=BC=93=E5=AD=98=E6=97=A0=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/modules/permission.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index dcb3cd4..ed64e46 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -100,6 +100,10 @@ export const usePermissionStore = defineStore('permission', () => { } if (lastRouter) { el.path = lastRouter.path + '/' + el.path; + if (el.children && el.children.length) { + children = children.concat(filterChildren(el.children, el)) + return + } } children = children.concat(el); }); From 35bebf403ca0729174d49e86feb8fb6e468c69de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Mon, 13 Nov 2023 13:02:09 +0800 Subject: [PATCH 14/15] =?UTF-8?q?update=20=E9=80=82=E9=85=8D=20websocket?= =?UTF-8?q?=E5=9C=A8https=E4=B8=8B=E7=9A=84=E8=BF=9E=E6=8E=A5=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/index.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/index.vue b/src/views/index.vue index 3bb7396..b86c019 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -99,7 +99,8 @@ import { initWebSocket } from '@/utils/websocket'; onMounted(() => { - initWebSocket("ws://" + window.location.host + import.meta.env.VITE_APP_BASE_API + "/resource/websocket"); + let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://' + initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + "/resource/websocket"); }); const goTarget = (url:string) => { From 6e6062e824dc53b0c2fcb54bd87c87c6b438be39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Tue, 14 Nov 2023 10:51:12 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=F0=9F=98=B4=E5=8F=91=E5=B8=83=20vue=20?= =?UTF-8?q?=E7=89=88=E6=9C=AC=205.1.1=20=E4=B8=8E=20cloud=20=E7=89=88?= =?UTF-8?q?=E6=9C=AC2.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/views/index.vue | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9b26e96..13e0f92 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi-vue-plus", - "version": "5.1.0", + "version": "5.1.1", "description": "RuoYi-Vue-Plus多租户管理系统", "author": "LionLi", "license": "MIT", diff --git a/src/views/index.vue b/src/views/index.vue index b86c019..7f658d8 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -33,7 +33,7 @@ * 部署方式 Docker 容器编排 一键部署业务集群
* 国际化 SpringMessage Spring标准国际化方案

-

当前版本: v5.1.0

+

当前版本: v5.1.1

¥免费开源

@@ -78,7 +78,7 @@ * 分布式监控 Prometheus、Grafana 全方位性能监控
* 其余与 Vue 版本一致

-

当前版本: v2.1.0

+

当前版本: v2.1.1

¥免费开源