当前位置:   article > 正文

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

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

更多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里增加消息组件

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

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

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

  1. <template>
  2. <div>
  3. <a-popover trigger="click" placement="bottomRight" :autoAdjustOverflow="true" :arrowPointAtCenter="true"
  4. overlayClassName="header-notice-wrapper" @visibleChange="handleHoverChange"
  5. :overlayStyle="{ width: '400px', top: '50px' }">
  6. <template #content>
  7. <a-spin :spinning="loadding">
  8. <a-tabs>
  9. <a-tab-pane :tab="msg1Title" key="1">
  10. <a-list>
  11. <a-list-item :key="index" v-for="(record, index) in notice1">
  12. <div style="margin-left: 5%;width: 50%">
  13. <p><a @click="showNoticeList(record)">{{ record.titile }}</a></p>
  14. <p style="color: rgba(0,0,0,.45);margin-bottom: 0px">{{ record.createTime }} 发布</p>
  15. </div>
  16. <div style="text-align: right">
  17. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'L'" color="blue">一般消息</a-tag>
  18. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'M'" color="orange">重要消息</a-tag>
  19. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'H'" color="red">紧急消息</a-tag>
  20. </div>
  21. </a-list-item>
  22. <div style="margin-top: 5px;text-align: center">
  23. <a-button @click="toMyNotice()" type="dashed" block>查看更多</a-button>
  24. </div>
  25. </a-list>
  26. </a-tab-pane>
  27. <a-tab-pane :tab="msg2Title" key="2">
  28. <a-list>
  29. <a-list-item :key="index" v-for="(record, index) in notice2">
  30. <div style="margin-left: 5%;width: 50%">
  31. <p><a @click="showNoticeList(record)">{{ record.titile }}</a></p>
  32. <p style="color: rgba(0,0,0,.45);margin-bottom: 0px">{{ record.createTime }} 发布</p>
  33. </div>
  34. <div style="text-align: right">
  35. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'L'" color="blue">一般消息</a-tag>
  36. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'M'" color="orange">重要消息</a-tag>
  37. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'H'" color="red">紧急消息</a-tag>
  38. </div>
  39. </a-list-item>
  40. <div style="margin-top: 5px;text-align: center">
  41. <a-button @click="toMyNotice()" type="dashed" block>查看更多</a-button>
  42. </div>
  43. </a-list>
  44. </a-tab-pane>
  45. <a-tab-pane :tab="msg3Title" key="3">
  46. <a-list>
  47. <a-list-item :key="index" v-for="(record, index) in notice3">
  48. <div style="margin-left: 5%;width: 50%">
  49. <p><a @click="showNoticeList(record)">{{ record.titile }}</a></p>
  50. <p style="color: rgba(0,0,0,.45);margin-bottom: 0px">{{ record.createTime }} 发布</p>
  51. </div>
  52. <div style="text-align: right">
  53. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'L'" color="blue">一般消息</a-tag>
  54. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'M'" color="orange">重要消息</a-tag>
  55. <a-tag @click="showNoticeList(record)" v-if="record.priority === 'H'" color="red">紧急消息</a-tag>
  56. </div>
  57. </a-list-item>
  58. <div style="margin-top: 5px;text-align: center">
  59. <a-button @click="toMyNotice()" type="dashed" block>查看更多</a-button>
  60. </div>
  61. </a-list>
  62. </a-tab-pane>
  63. </a-tabs>
  64. </a-spin>
  65. </template>
  66. <span @click="fetchNotice" class="header-notice">
  67. <a-badge :count="msgTotal">
  68. <svg-icon icon-class="bell" style="width: 18px;height:18px;" />
  69. </a-badge>
  70. </span>
  71. <show-notice ref="showNoticeRef" @ok="modalFormOk"></show-notice>
  72. <dynamic-notice ref="showDynamNoticeRef" :path="openPath" :formData="formData" />
  73. </a-popover>
  74. </div>
  75. </template>
  76. <script setup lang="ts">
  77. import ShowNotice from './ShowNotice.vue'
  78. import useUserStore from '@/store/modules/user';
  79. import DynamicNotice from './DynamicNotice'
  80. import { ElNotification } from "element-plus";
  81. import { listByUser, updateUserIdAndNotice } from "@/api/system/notice";
  82. const router = useRouter();
  83. const userStore = useUserStore();
  84. const loadding = ref(false)
  85. const hovered = ref(false)
  86. const notice1 = ref<any>([])
  87. const notice2 = ref<any>([])
  88. const notice3 = ref<any>([])
  89. const msg1Count = ref("0")
  90. const msg2Count = ref("0")
  91. const msg3Count = ref("0")
  92. const msg1Title = ref("通知(0)")
  93. const msg2Title = ref("")
  94. const msg3Title = ref("")
  95. const stopTimer = ref(false)
  96. let websock : any = null; // websocket 实例
  97. const lockReconnect = ref(false)
  98. const formData = ref<any>({})
  99. const openPath = ref('')
  100. const showDynamNoticeRef = ref(DynamicNotice)
  101. const showNoticeRef = ref(ShowNotice)
  102. const loadData = () => {
  103. try {
  104. // 获取系统消息
  105. listByUser().then((res) => {
  106. console.log("listByUser res",res);
  107. if (res.code == 200) {
  108. notice1.value = res.data.anntMsgList;
  109. msg1Count.value = res.data.anntMsgTotal;
  110. msg1Title.value = "通知(" + res.data.anntMsgTotal + ")";
  111. notice2.value = res.data.sysMsgList;
  112. msg2Count.value = res.data.sysMsgTotal;
  113. msg2Title.value = "系统消息(" + res.data.sysMsgTotal + ")";
  114. notice3.value = res.data.todealMsgList;
  115. msg3Count.value = res.data.todealMsgTotal;
  116. msg3Title.value = "待办消息(" + res.data.todealMsgTotal + ")";
  117. }
  118. }).catch(error => {
  119. console.log("系统消息通知异常", error); //这行打印permissionName is undefined
  120. stopTimer.value = true;
  121. console.log("清理timer");
  122. });
  123. } catch (err) {
  124. stopTimer.value = true;
  125. console.log("通知异常", err);
  126. }
  127. }
  128. const fetchNotice = () => {
  129. if (loadding.value) {
  130. loadding.value = false
  131. return
  132. }
  133. loadding.value = true
  134. setTimeout(() => {
  135. loadding.value = false
  136. }, 200)
  137. }
  138. const showNoticeList = (record: any) => {
  139. updateUserIdAndNotice({
  140. noticeId: record.noticeId
  141. }).then((res) => {
  142. if (res.code == 200) {
  143. loadData();
  144. }
  145. });
  146. hovered.value = false;
  147. if (record.openType === 'component') {
  148. openPath.value = record.openPage;
  149. formData.value = {
  150. id: record.busId
  151. };
  152. showDynamNoticeRef.value.detail(record.openPage);
  153. } else {
  154. console.log("showNoticeList showNoticeRef",showNoticeRef.value)
  155. showNoticeRef.value.detail(record);
  156. }
  157. }
  158. const toMyNotice = () => {
  159. router.push({
  160. path: '/personal/mynotice'
  161. });
  162. }
  163. const modalFormOk = () =>{
  164. }
  165. const handleHoverChange = (visible: any) => {
  166. hovered.value = visible;
  167. }
  168. const initWebSocket = () => {
  169. // WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
  170. var userName = userStore.name;
  171. //var url = import.meta.env.VITE_APP_WS_API + "/websocket/" + userName + "?Authorization=Bearer " + getToken() + "&clientid=" + import.meta.env.VITE_APP_CLIENT_ID;
  172. var url = import.meta.env.VITE_APP_WS_API + "/websocket/" + userName;
  173. console.log("initWebSocket url=",url);
  174. websock = new WebSocket(url);
  175. websock.onopen = websocketOnopen;
  176. websock.onerror = websocketOnerror;
  177. websock.onmessage = websocketOnmessage;
  178. websock.onclose = websocketOnclose;
  179. }
  180. const websocketOnopen = () => {
  181. console.log("WebSocket连接成功");
  182. }
  183. const websocketOnerror = (e) => {
  184. console.log("WebSocket连接发生错误");
  185. reconnect();
  186. }
  187. const websocketOnmessage = (e) => {
  188. console.log("-----接收消息-------", e);
  189. console.log("-----接收消息-------", e.data);
  190. var data = eval("(" + e.data + ")"); //解析对象
  191. if (data.cmd == "topic") {
  192. //系统通知
  193. loadData();
  194. ElNotification({ //websocket消息通知弹出
  195. title: 'websocket消息通知',
  196. message: data.msgTxt,
  197. type: 'success',
  198. duration: 1000
  199. })
  200. } else if (data.cmd == "user") {
  201. //用户消息
  202. loadData();
  203. ElNotification({
  204. title: 'websocket消息通知',
  205. message: data.msgTxt,
  206. type: 'success',
  207. duration: 1000
  208. })
  209. }
  210. }
  211. const websocketOnclose = (e) => {
  212. console.log("connection closed (" + e + ")");
  213. if (e) {
  214. console.log("connection closed (" + e.code + ")");
  215. }
  216. reconnect();
  217. }
  218. const websocketSend = (text) => { // 数据发送
  219. try {
  220. websock.send(text);
  221. } catch (err) {
  222. console.log("send failed (" + err.code + ")");
  223. }
  224. }
  225. const openNotification = (data) =>{
  226. var text = data.msgTxt;
  227. const key = `open${Date.now()}`;
  228. ElNotification({
  229. title: '消息提醒',
  230. message: text,
  231. type: 'success',
  232. duration: 1000
  233. })
  234. }
  235. const reconnect = () => {
  236. if (lockReconnect.value) return;
  237. lockReconnect.value = true;
  238. //没连接上会一直重连,设置延迟避免请求过多
  239. setTimeout(function() {
  240. console.info("尝试重连...");
  241. initWebSocket();
  242. lockReconnect.value = false;
  243. }, 5000);
  244. }
  245. const showDetail = (key, data) => {
  246. ElNotification[key].close();
  247. var id = data.msgId;
  248. getAction(url.queryById, {
  249. id: id
  250. }).then((res) => {
  251. if (res.success) {
  252. var record = res.result;
  253. showNotice(record);
  254. }
  255. })
  256. }
  257. const msgTotal = computed(() => {
  258. return parseInt(msg1Count.value) + parseInt(msg2Count.value) + parseInt(msg3Count.value);
  259. })
  260. onMounted(() => {
  261. loadData();
  262. initWebSocket();
  263. })
  264. onUnmounted(() => {
  265. websocketOnclose('');
  266. })
  267. </script>
  268. <style lang="css">
  269. .header-notice-wrapper {
  270. top: 50px !important;
  271. }
  272. </style>
  273. <style lang="less" scoped>
  274. .header-notice {
  275. display: inline-block;
  276. transition: all 0.3s;
  277. span {
  278. vertical-align: initial;
  279. }
  280. }
  281. </style>

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

  1. <template>
  2. <n-modal
  3. :title="title"
  4. :width="modelStyle.width"
  5. :visible="visible"
  6. :bodyStyle ="bodyStyle"
  7. @cancel="handleCancel"
  8. >
  9. <template #footer>
  10. <a-button key="back" @click="handleCancel">关闭</a-button>
  11. <a-button v-if="recordDetail.openType==='url'" type="primary" @click="toHandle">去处理</a-button>
  12. </template>
  13. <a-card class="daily-article" :loading="loading">
  14. <a-card-meta
  15. :title="recordDetail.noticeTitle"
  16. :description="'发布人:'+recordDetail.sender + ' 发布时间: ' + recordDetail.sendTime">
  17. </a-card-meta>
  18. <a-divider />
  19. <span v-html="recordDetail.noticeContent" class="article-content"></span>
  20. </a-card>
  21. </n-modal>
  22. </template>
  23. <script setup lang="ts" name="ShowNotice">
  24. import NModal from './NModal'
  25. const router = useRouter();
  26. const title = ref("通知消息")
  27. const recordDetail = ref<any>({})
  28. const visible = ref(false)
  29. const loading = ref(false)
  30. const bodyStyle = ref({
  31. padding: "0",
  32. height:(window.innerHeight*0.8)+"px",
  33. "overflow-y":"auto",
  34. })
  35. const modelStyle = ref({
  36. width: '60%',
  37. style: { top: '20px' },
  38. fullScreen: false
  39. })
  40. const detail = (record: any) => {
  41. visible.value = true;
  42. recordDetail.value = toRaw(record);
  43. }
  44. const handleCancel = () => {
  45. visible.value = false;
  46. }
  47. const toHandle = () => {
  48. if(recordDetail.value.openType==='url'){
  49. visible.value = false;
  50. //链接跳转
  51. router.push({path: recordDetail.value.openPage})
  52. }
  53. }
  54. //暴露detail方法
  55. defineExpose({
  56. detail
  57. });
  58. onMounted(() => {
  59. console.log("ShowNotice visible",visible)
  60. })
  61. </script>
  62. <style lang="less" scoped>
  63. .announcementCustomModal{
  64. .ant-modal-header {
  65. border: none;
  66. display: inline-block;
  67. position: absolute;
  68. z-index: 1;
  69. right: 56px;
  70. padding: 0;
  71. .ant-modal-title{
  72. .custom-btn{
  73. width: 56px;
  74. height: 56px;
  75. border: none;
  76. box-shadow: none;
  77. }
  78. }
  79. }
  80. .daily-article{
  81. border-bottom: 0;
  82. }
  83. }
  84. .daily-article {
  85. .article-button {
  86. font-size: 1.2rem !important;
  87. }
  88. .ant-card-body {
  89. padding: 18px !important;
  90. }
  91. .ant-card-head {
  92. padding: 0 1rem;
  93. }
  94. .ant-card-meta {
  95. margin-bottom: 1rem;
  96. }
  97. .article-content {
  98. p {
  99. word-wrap: break-word;
  100. word-break: break-all;
  101. text-overflow: initial;
  102. white-space: normal;
  103. font-size: .9rem !important;
  104. margin-bottom: .8rem;
  105. }
  106. :deep(a) {
  107. color: #1890ff;
  108. }
  109. }
  110. }
  111. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/468699
推荐阅读
相关标签
  

闽ICP备14008679号