ruoyi-nbcio-plus基于vue3的flowable的websocket消息组件的升级修改(一)

devtools/2024/9/19 18:38:49/ 标签: websocket, flowable, ruoyi-nbcio, 前端, vue3

更多ruoyi-nbcio功能请看演示系统

gitee源代码地址

前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio

演示地址:RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/

更多nbcio-boot功能请看演示系统 

gitee源代码地址

后端代码: https://gitee.com/nbacheng/nbcio-boot

前端代码:https://gitee.com/nbacheng/nbcio-vue.git

在线演示(包括H5) : http://122.227.135.243:9888

1、在navbar.vue里增加消息组件

<!-- 消息 --><el-tooltip :content="$t('navbar.message')" effect="dark" placement="bottom"><header-notice id="message" class="right-menu-item hover-effect" /></el-tooltip>

就是在右上角显示消息图标bell

2、HeadNotice.vue文件vue3版本修改如下:

<template><div><a-popover trigger="click" placement="bottomRight" :autoAdjustOverflow="true" :arrowPointAtCenter="true"overlayClassName="header-notice-wrapper" @visibleChange="handleHoverChange":overlayStyle="{ width: '400px', top: '50px' }"><template #content><a-spin :spinning="loadding"><a-tabs><a-tab-pane :tab="msg1Title" key="1"><a-list><a-list-item :key="index" v-for="(record, index) in notice1"><div style="margin-left: 5%;width: 50%"><p><a @click="showNoticeList(record)">{{ record.titile }}</a></p><p style="color: rgba(0,0,0,.45);margin-bottom: 0px">{{ record.createTime }} 发布</p></div><div style="text-align: right"><a-tag @click="showNoticeList(record)" v-if="record.priority === 'L'" color="blue">一般消息</a-tag><a-tag @click="showNoticeList(record)" v-if="record.priority === 'M'" color="orange">重要消息</a-tag><a-tag @click="showNoticeList(record)" v-if="record.priority === 'H'" color="red">紧急消息</a-tag></div></a-list-item><div style="margin-top: 5px;text-align: center"><a-button @click="toMyNotice()" type="dashed" block>查看更多</a-button></div></a-list></a-tab-pane><a-tab-pane :tab="msg2Title" key="2"><a-list><a-list-item :key="index" v-for="(record, index) in notice2"><div style="margin-left: 5%;width: 50%"><p><a @click="showNoticeList(record)">{{ record.titile }}</a></p><p style="color: rgba(0,0,0,.45);margin-bottom: 0px">{{ record.createTime }} 发布</p></div><div style="text-align: right"><a-tag @click="showNoticeList(record)" v-if="record.priority === 'L'" color="blue">一般消息</a-tag><a-tag @click="showNoticeList(record)" v-if="record.priority === 'M'" color="orange">重要消息</a-tag><a-tag @click="showNoticeList(record)" v-if="record.priority === 'H'" color="red">紧急消息</a-tag></div></a-list-item><div style="margin-top: 5px;text-align: center"><a-button @click="toMyNotice()" type="dashed" block>查看更多</a-button></div></a-list></a-tab-pane><a-tab-pane :tab="msg3Title" key="3"><a-list><a-list-item :key="index" v-for="(record, index) in notice3"><div style="margin-left: 5%;width: 50%"><p><a @click="showNoticeList(record)">{{ record.titile }}</a></p><p style="color: rgba(0,0,0,.45);margin-bottom: 0px">{{ record.createTime }} 发布</p></div><div style="text-align: right"><a-tag @click="showNoticeList(record)" v-if="record.priority === 'L'" color="blue">一般消息</a-tag><a-tag @click="showNoticeList(record)" v-if="record.priority === 'M'" color="orange">重要消息</a-tag><a-tag @click="showNoticeList(record)" v-if="record.priority === 'H'" color="red">紧急消息</a-tag></div></a-list-item><div style="margin-top: 5px;text-align: center"><a-button @click="toMyNotice()" type="dashed" block>查看更多</a-button></div></a-list></a-tab-pane></a-tabs></a-spin></template><span @click="fetchNotice" class="header-notice"><a-badge :count="msgTotal"><svg-icon icon-class="bell" style="width: 18px;height:18px;" /></a-badge></span><show-notice ref="showNoticeRef" @ok="modalFormOk"></show-notice><dynamic-notice ref="showDynamNoticeRef" :path="openPath" :formData="formData" /></a-popover></div>
</template><script setup lang="ts">import ShowNotice from './ShowNotice.vue'import useUserStore from '@/store/modules/user';import DynamicNotice from './DynamicNotice'import { ElNotification } from "element-plus";import { listByUser, updateUserIdAndNotice } from "@/api/system/notice";const router = useRouter();const userStore = useUserStore();const loadding = ref(false)const hovered = ref(false)const notice1 = ref<any>([])const notice2 = ref<any>([])const notice3 = ref<any>([])const msg1Count = ref("0")const msg2Count = ref("0")const msg3Count = ref("0")const msg1Title = ref("通知(0)")const msg2Title = ref("")const msg3Title = ref("")const stopTimer = ref(false)let   websock : any = null; // websocket 实例const lockReconnect = ref(false)const formData = ref<any>({})const openPath = ref('')const showDynamNoticeRef = ref(DynamicNotice)const showNoticeRef = ref(ShowNotice)const loadData = () => {try {// 获取系统消息listByUser().then((res) => {console.log("listByUser res",res);if (res.code == 200) {notice1.value = res.data.anntMsgList;msg1Count.value = res.data.anntMsgTotal;msg1Title.value = "通知(" + res.data.anntMsgTotal + ")";notice2.value = res.data.sysMsgList;msg2Count.value = res.data.sysMsgTotal;msg2Title.value = "系统消息(" + res.data.sysMsgTotal + ")";notice3.value = res.data.todealMsgList;msg3Count.value = res.data.todealMsgTotal;msg3Title.value = "待办消息(" + res.data.todealMsgTotal + ")";}}).catch(error => {console.log("系统消息通知异常", error); //这行打印permissionName is undefinedstopTimer.value = true;console.log("清理timer");});} catch (err) {stopTimer.value = true;console.log("通知异常", err);}}const fetchNotice = () => {if (loadding.value) {loadding.value = falsereturn}loadding.value = truesetTimeout(() => {loadding.value = false}, 200)}const showNoticeList = (record: any) => {updateUserIdAndNotice({noticeId: record.noticeId}).then((res) => {if (res.code == 200) {loadData();}});hovered.value = false;if (record.openType === 'component') {openPath.value = record.openPage;formData.value = {id: record.busId};showDynamNoticeRef.value.detail(record.openPage);} else {console.log("showNoticeList showNoticeRef",showNoticeRef.value)showNoticeRef.value.detail(record);}}const toMyNotice = () => {router.push({path: '/personal/mynotice'});}const modalFormOk = () =>{}const handleHoverChange = (visible: any) => {hovered.value = visible;}const initWebSocket = () => {// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于httpsvar userName = userStore.name;//var url = import.meta.env.VITE_APP_WS_API + "/websocket/" + userName  + "?Authorization=Bearer " + getToken() + "&clientid=" + import.meta.env.VITE_APP_CLIENT_ID;var url = import.meta.env.VITE_APP_WS_API + "/websocket/" + userName;console.log("initWebSocket url=",url);websock = new WebSocket(url);websock.onopen = websocketOnopen;websock.onerror = websocketOnerror;websock.onmessage = websocketOnmessage;websock.onclose = websocketOnclose;}const websocketOnopen = () => {console.log("WebSocket连接成功");}const websocketOnerror = (e) => {console.log("WebSocket连接发生错误");reconnect();}const websocketOnmessage = (e) => {console.log("-----接收消息-------", e);console.log("-----接收消息-------", e.data);var data = eval("(" + e.data + ")"); //解析对象if (data.cmd == "topic") {//系统通知loadData();ElNotification({ //websocket消息通知弹出title: 'websocket消息通知',message: data.msgTxt,type: 'success',duration: 1000})} else if (data.cmd == "user") {//用户消息loadData();ElNotification({title: 'websocket消息通知',message: data.msgTxt,type: 'success',duration: 1000})}}const websocketOnclose = (e) => {console.log("connection closed (" + e + ")");if (e) {console.log("connection closed (" + e.code + ")");}reconnect();}const websocketSend = (text) => { // 数据发送try {websock.send(text);} catch (err) {console.log("send failed (" + err.code + ")");}}const openNotification = (data) =>{var text = data.msgTxt;const key = `open${Date.now()}`;ElNotification({title: '消息提醒',message: text,type: 'success',duration: 1000})}const reconnect = () => {if (lockReconnect.value) return;lockReconnect.value = true;//没连接上会一直重连,设置延迟避免请求过多setTimeout(function() {console.info("尝试重连...");initWebSocket();lockReconnect.value = false;}, 5000);}const showDetail = (key, data) => {ElNotification[key].close();var id = data.msgId;getAction(url.queryById, {id: id}).then((res) => {if (res.success) {var record = res.result;showNotice(record);}})}const msgTotal = computed(() => {return parseInt(msg1Count.value) + parseInt(msg2Count.value) + parseInt(msg3Count.value);})onMounted(() => {loadData();initWebSocket();})onUnmounted(() => {websocketOnclose('');})
</script><style lang="css">.header-notice-wrapper {top: 50px !important;}
</style>
<style lang="less" scoped>.header-notice {display: inline-block;transition: all 0.3s;span {vertical-align: initial;}}
</style>

3、ShowNotice.vue文件vue3版本修改如下:

<template><n-modal:title="title":width="modelStyle.width":visible="visible":bodyStyle ="bodyStyle"@cancel="handleCancel"><template #footer><a-button key="back" @click="handleCancel">关闭</a-button><a-button v-if="recordDetail.openType==='url'" type="primary" @click="toHandle">去处理</a-button></template><a-card class="daily-article" :loading="loading"><a-card-meta:title="recordDetail.noticeTitle":description="'发布人:'+recordDetail.sender + ' 发布时间: ' + recordDetail.sendTime"></a-card-meta><a-divider /><span v-html="recordDetail.noticeContent" class="article-content"></span></a-card></n-modal>
</template><script setup lang="ts" name="ShowNotice">import NModal from './NModal'const router = useRouter();const title = ref("通知消息")const recordDetail = ref<any>({})const visible = ref(false)const loading = ref(false)const bodyStyle = ref({padding: "0",height:(window.innerHeight*0.8)+"px","overflow-y":"auto",})const modelStyle = ref({width: '60%',style: { top: '20px' },fullScreen: false})const detail = (record: any) => {visible.value = true;recordDetail.value = toRaw(record);}const handleCancel = () => {visible.value = false;}const toHandle = () => {if(recordDetail.value.openType==='url'){visible.value = false;//链接跳转router.push({path: recordDetail.value.openPage})}}//暴露detail方法defineExpose({detail});onMounted(() => {console.log("ShowNotice visible",visible)})</script><style lang="less" scoped>.announcementCustomModal{.ant-modal-header {border: none;display: inline-block;position: absolute;z-index: 1;right: 56px;padding: 0;.ant-modal-title{.custom-btn{width: 56px;height: 56px;border: none;box-shadow: none;}}}.daily-article{border-bottom: 0;}}.daily-article {.article-button {font-size: 1.2rem !important;}.ant-card-body {padding: 18px !important;}.ant-card-head {padding: 0 1rem;}.ant-card-meta {margin-bottom: 1rem;}.article-content {p {word-wrap: break-word;word-break: break-all;text-overflow: initial;white-space: normal;font-size: .9rem !important;margin-bottom: .8rem;}:deep(a) {color: #1890ff;}}}
</style>


http://www.ppmy.cn/devtools/13947.html

相关文章

Java之多态

一、多态前言 1.为什么要使用多态 Java中使用多态的主要目的是提高代码的可重用性和扩展性&#xff0c;使得代码更加灵活和易于维护。通过多态&#xff0c;我们可以将不同的对象看做是同一种类型&#xff0c;从而使得我们可以使用同一种接口来操作这些对象&#xff0c;而不必…

如何使用自定义Promptbooks优化您的安全工作流程

在当今的数字化时代&#xff0c;安全工作流程的优化变得前所未有的重要。安全团队需要快速、有效地响应安全事件&#xff0c;以保护组织的数据和资产。Microsoft Copilot for Security提供了一种强大的工具——自定义Promptbooks&#xff0c;它可以帮助安全专家通过自动化和定制…

springboot项目整合kafka实现消息队列

一、Docker镜像、容器准备&#xff1a; 1.1拉取镜像&#xff1a; 前提是虚拟机安装了docker&#xff0c;可以自行看其他文章进行安装 docker pull ubuntu/kafka docker pull zookeeper1.2运行容器 先启动zookeeper容器&#xff0c;因为kafka依赖于zookeeper docker run -d …

【数据仓库工具箱】DW/BI系统的核心元素和基本要求

核心元素 DW/BI 环境划分为4个不同的&#xff0c;各具特色的组成部分。分别是&#xff1a;操作型源数据&#xff0c;ETL系统&#xff0c;数据展现和商业智能应用。 操作型源数据 记录的是操作型系统&#xff0c;用于获取业务事务。源数据关注的是处理性能和可用性。源系统一般…

七星创客新零售系统:颠覆性商业模式的崛起

大家好&#xff0c;我是微三云周丽&#xff0c;今天给大家分析当下市场比较火爆的商业模式&#xff01; 小编今天跟大伙们分享什么是七星创客新零售系统&#xff1f; 随着经济的快速发展和科技的不断进步&#xff0c;商业模式的革新成为了企业发展的关键。在这个新旧动能转换、…

【AI开发:音频】二、GPT-SoVITS使用方法和过程中出现的问题(GPU版)

1.FileNotFoundError: [Errno 2] No such file or directory: logs/guanshenxxx/2-name2text-0.txt 这个问题中包含了两个&#xff1a; 第一个&#xff1a;No module named pyopenjtalk 我的电脑出现的就是这个 解决&#xff1a;pip install pyopenjtalk 第二个&#xff1a…

docker 安装geoipupdate

前提是docker已安装 一&#xff1a;执行命令&#xff1a; docker run --env-file /usr/local/etc/GeoIP.conf -v /usr/local/GeoIP2:/usr/share/GeoIP ghcr.io/maxmind/geoipupdate /usr/local/etc/GeoIP.conf &#xff1a;本地配置的账号&#xff0c;秘钥 GEOIPUPDATE_AC…

低视力者出行升级:适配服务助力双手解放与环境感知

作为一名资深记者&#xff0c;我有幸深入了解并记录低视力者在日常出行中所面临的挑战与解决方案。近年来&#xff0c;低视力者辅助设备适配服务提供领域的创新成果&#xff0c;尤其是结合手机应用的辅助设备&#xff0c;正在以人性化、智能化的方式&#xff0c;帮助低视力者实…

[C++][算法基础]求a的b次方模p的值(快速幂)

给定 n 组 &#xff0c;对于每组数据&#xff0c;求出 的值。 输入格式 第一行包含整数 n。 接下来 n 行&#xff0c;每行包含三个整数 。 输出格式 对于每组数据&#xff0c;输出一个结果&#xff0c;表示 的值。 每个结果占一行。 数据范围 1≤n≤100000, 1≤≤2 …

Leetcode算法训练日记 | day35

专题九 贪心算法 一、柠檬水找零 1.题目 Leetcode&#xff1a;第 860 题 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品&#xff0c;&#xff08;按账单 bills 支付的顺序&#xff09;一次购买一杯。 每位顾客只买一杯柠檬水&#xff0c;然…

视频评价工具AVQT介绍

AVQT介绍 AVQT(Advanced Video Quality Tool)是一个用于评估压缩视频感知质量的工具。它通过模拟人类如何评价压缩视频的质量来进行工作。AVQT 是是苹果在 WWDC 21 上推出的一款评估视频感知质量的工具。AVQT可以用于计算视频的帧级和片段级得分,其中片段通常持续几秒钟。这…

RabbitMQ spring boot TTL延时消费

关于延时消费主要分为两种实现&#xff0c;一种是rabbitmq的TTL机制&#xff0c;一种是rabbitmq的插件实现。 实现一&#xff1a;TTL 1、设置队列的过期时间 2、设置消息的过期时间 添加相关maven依赖 <dependency><groupId>org.springframework.boot</grou…

如何让AI生成自己喜欢的歌曲-AI音乐创作的正确方式 - 第507篇

历史文章 AI音乐&#xff0c;8大变现方式——Suno&#xff1a;音乐版的ChatGPT - 第505篇 日赚800&#xff0c;利用淘宝/闲鱼进行AI音乐售卖实操 - 第506篇 导读 在使用AI生成音乐&#xff08;AI写歌&#xff09;的时候&#xff0c;你是不是有这样的困惑&#xff1a; &…

黑客零基础入门教程:从零开始学习黑客技术

黑客技术往往被误解&#xff0c;但实际上&#xff0c;学习黑客技术可以帮助我们更好地理解网络安全&#xff0c;保护个人信息免受攻击。本文为零基础的朋友提供了一个黑客技术的学习入门指南&#xff0c;帮助你从基础到实践逐步深入了解和掌握相关技能。 了解基本概念 在开始…

SpringBoot+Vue开发记录(四)

说明&#xff1a; 本篇文章的主要内容是软件架构以及项目的前端Vue创建 一、软件架构 我道听途说的&#xff0c;听说这个东西很关键很重要什么的。 软件架构&#xff08;software architecture&#xff09;是一个系统的草图,是一系列相关的抽象模式&#xff0c;用于指导大型软…

Ajax技术是啥?在web开发中有啥用?

一、Ajax是啥&#xff1f; Ajax技术是一种让网页能在不完全刷新页面的情况下&#xff0c;通过JavaScript与服务器进行异步数据交换&#xff0c;并更新部分网页内容的技术。 简单来说&#xff0c;Ajax的核心原理就是在JavaScript的控制下&#xff0c;网页悄悄地向服务器请求数…

新加坡VPS服务器Linux系统的安全性如何增强

增强新加坡VPS服务器上Linux系统的安全性是至关重要的&#xff0c;以下是一些常见的方法和建议&#xff1a; 更新系统和软件&#xff1a; 定期更新操作系统和安装的软件包&#xff0c;确保系统中的所有组件都是最新版本&#xff0c;以修补已知的漏洞和安全问题。 配置防火墙&am…

计算机网络原原理学习资料分享---第一章/第一节(为有梦想的自己加油!)

计算机网络原理 课程知识框架 计算机网络原理 课程框架 第一章 计算机网络概述 重点 第二章 网络应用 重点 第三章 传输层 重点 难点 第四章 网络层…

Kamailio 的 uuid_kill

Kamailio 是否有类似 FreeSWITCH 的 uuid_kill 命令 试了试&#xff0c;发现还真的有 如果正在振铃&#xff0c;那么 tm.cancel 可以结束呼叫&#xff0c;参考链接&#xff1a; https://kamailio.org/docs/modules/5.5.x/modules/tm.html#tm.rpc.cancel 如果已经应答&#…

【程序创建的技巧】

文章目录 导语名词源代码目标代码&#xff08;object code&#xff09;可执行代码 创建源代码文件编译和链接UNIX编译和链接Linux编译和链接Windows命令行编译器Windows编译器 总结 导语 假设您编写了一个 C 程序。 如何让它运行起来呢&#xff1f; 具体的步骤取决于计算机环境…