This commit is contained in:
xd 2024-04-24 13:16:34 +08:00
parent e4bdf650bb
commit 9681fd1a48
10 changed files with 294 additions and 125 deletions

View File

@ -1,6 +1,14 @@
package com.ruoyi.web.controller.system;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.WebsocketConst;
import com.ruoyi.framework.websocket.WebSocketServer;
import com.ruoyi.framework.websocket.WebSocketUsers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
@ -22,7 +30,7 @@ import com.ruoyi.system.service.ISysNoticeService;
/**
* 公告 信息操作处理
*
*
* @author ruoyi
*/
@RestController
@ -32,6 +40,9 @@ public class SysNoticeController extends BaseController
@Autowired
private ISysNoticeService noticeService;
@Autowired
private WebSocketServer webSocketServer;
/**
* 获取通知公告列表
*/
@ -63,6 +74,13 @@ public class SysNoticeController extends BaseController
public AjaxResult add(@Validated @RequestBody SysNotice notice)
{
notice.setCreateBy(getUsername());
JSONObject obj = new JSONObject();
obj.put(WebsocketConst.MSG_ID, notice.getNoticeId());
obj.put(WebsocketConst.MSG_TITLE, notice.getNoticeTitle());
obj.put(WebsocketConst.MSG_CONTENT, notice.getNoticeContent());
WebSocketUsers.sendMessageToUsersByText(obj.toString());
return toAjax(noticeService.insertNotice(notice));
}
@ -88,4 +106,21 @@ public class SysNoticeController extends BaseController
{
return toAjax(noticeService.deleteNoticeByIds(noticeIds));
}
/**
* 导航面板 消息通知
* @return
*/
@GetMapping("/navbarNoticelist")
public Map<String, List<SysNotice>> navbarNoticelist()
{
List<SysNotice> list = noticeService.navbarNoticelist();
Map<String, List<SysNotice>> groupedByNoticeType = list.stream()
.collect(Collectors.groupingBy(SysNotice::getNoticeType));
for(String key:groupedByNoticeType.keySet()){
List<SysNotice> lt = groupedByNoticeType.get(key);
lt.sort((t1, t2) -> t2.getCreateTime().compareTo(t1.getCreateTime()));
}
return groupedByNoticeType;
}
}

View File

@ -0,0 +1,17 @@
package com.ruoyi.common.constant;
/**
* 消息推送通用常量
*
* @author ruoyi
*/
public class WebsocketConst {
/** 消息ID */
public static final String MSG_ID = "noticeId";
/** 消息TITLE */
public static final String MSG_TITLE = "noticeTitle";
/** 消息CONTENT */
public static final String MSG_CONTENT = "noticeContent";
}

View File

@ -5,14 +5,14 @@ import com.ruoyi.system.domain.SysNotice;
/**
* 通知公告表 数据层
*
*
* @author ruoyi
*/
public interface SysNoticeMapper
{
/**
* 查询公告信息
*
*
* @param noticeId 公告ID
* @return 公告信息
*/
@ -20,7 +20,7 @@ public interface SysNoticeMapper
/**
* 查询公告列表
*
*
* @param notice 公告信息
* @return 公告集合
*/
@ -28,7 +28,7 @@ public interface SysNoticeMapper
/**
* 新增公告
*
*
* @param notice 公告信息
* @return 结果
*/
@ -36,7 +36,7 @@ public interface SysNoticeMapper
/**
* 修改公告
*
*
* @param notice 公告信息
* @return 结果
*/
@ -44,7 +44,7 @@ public interface SysNoticeMapper
/**
* 批量删除公告
*
*
* @param noticeId 公告ID
* @return 结果
*/
@ -52,9 +52,15 @@ public interface SysNoticeMapper
/**
* 批量删除公告信息
*
*
* @param noticeIds 需要删除的公告ID
* @return 结果
*/
public int deleteNoticeByIds(Long[] noticeIds);
/**
* 消息推送信息获取
* @return
*/
List<SysNotice> navbarNoticelist();
}

View File

@ -5,14 +5,14 @@ import com.ruoyi.system.domain.SysNotice;
/**
* 公告 服务层
*
*
* @author ruoyi
*/
public interface ISysNoticeService
{
/**
* 查询公告信息
*
*
* @param noticeId 公告ID
* @return 公告信息
*/
@ -20,7 +20,7 @@ public interface ISysNoticeService
/**
* 查询公告列表
*
*
* @param notice 公告信息
* @return 公告集合
*/
@ -28,7 +28,7 @@ public interface ISysNoticeService
/**
* 新增公告
*
*
* @param notice 公告信息
* @return 结果
*/
@ -36,7 +36,7 @@ public interface ISysNoticeService
/**
* 修改公告
*
*
* @param notice 公告信息
* @return 结果
*/
@ -44,17 +44,23 @@ public interface ISysNoticeService
/**
* 删除公告信息
*
*
* @param noticeId 公告ID
* @return 结果
*/
public int deleteNoticeById(Long noticeId);
/**
* 批量删除公告信息
*
*
* @param noticeIds 需要删除的公告ID
* @return 结果
*/
public int deleteNoticeByIds(Long[] noticeIds);
/**
* 导航面板 消息通知
* @return
*/
List<SysNotice> navbarNoticelist();
}

View File

@ -12,7 +12,7 @@ import com.ruoyi.system.service.ISysNoticeService;
/**
* 公告 服务层实现
*
*
* @author ruoyi
*/
@Service
@ -23,7 +23,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService
/**
* 查询公告信息
*
*
* @param noticeId 公告ID
* @return 公告信息
*/
@ -40,7 +40,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService
/**
* 查询公告列表
*
*
* @param notice 公告信息
* @return 公告集合
*/
@ -61,7 +61,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService
/**
* 新增公告
*
*
* @param notice 公告信息
* @return 结果
*/
@ -76,7 +76,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService
/**
* 修改公告
*
*
* @param notice 公告信息
* @return 结果
*/
@ -91,7 +91,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService
/**
* 删除公告对象
*
*
* @param noticeId 公告ID
* @return 结果
*/
@ -103,7 +103,7 @@ public class SysNoticeServiceImpl implements ISysNoticeService
/**
* 批量删除公告信息
*
*
* @param noticeIds 需要删除的公告ID
* @return 结果
*/
@ -112,4 +112,13 @@ public class SysNoticeServiceImpl implements ISysNoticeService
{
return noticeMapper.deleteNoticeByIds(noticeIds);
}
/**
* 导航面板 消息通知
* @return
*/
@Override
public List<SysNotice> navbarNoticelist() {
return noticeMapper.navbarNoticelist();
}
}

View File

@ -86,4 +86,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach>
</delete>
<select id="navbarNoticelist" resultMap="SysNoticeResult">
<include refid="selectNoticeVo"/>
<where>
CONVERT(date, create_time) = CONVERT(date, GETDATE())
</where>
order by create_time desc
</select>
</mapper>

View File

@ -1,10 +0,0 @@
import request from '@/utils/request'
// 查询业务消息
export function getNoticeListTop3(query) {
return request({
url: '/system/notice/list',
method: 'get',
params: query
})
}

View File

@ -41,4 +41,13 @@ export function delNotice(noticeId) {
url: '/system/notice/' + noticeId,
method: 'delete'
})
}
}
// 导航面板 消息通知
export function navbarNoticelist(query) {
return request({
url: '/system/notice/navbarNoticelist',
method: 'get',
params: query
})
}

View File

@ -17,6 +17,8 @@
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>-->
<!--消息组件-->
<NavbarNotice class="right-menu-item hover-effect"></NavbarNotice>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="布局大小" effect="dark" placement="bottom">
@ -57,18 +59,9 @@ import Search from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
import settings from '@/settings'
import { getNoticeListTop3 } from "@/api/system/businessNotice";
import NavbarNotice from "@/layout/components/NavbarNotice.vue";
export default {
data() {
return {
url: "ws://localhost:3334/websocket/message",
message: "",
text_content: "",
ws: null,
};
},
components: {
Breadcrumb,
TopNav,
@ -77,7 +70,8 @@ export default {
SizeSelect,
Search,
RuoYiGit,
RuoYiDoc
RuoYiDoc,
NavbarNotice
},
computed: {
...mapGetters([
@ -102,87 +96,7 @@ export default {
}
}
},
mounted() {
/** 消息推送 */
this.notice();
const wsuri = this.url;
this.ws = new WebSocket(wsuri);
const self = this;
this.ws.onopen = function (event) {
//self.text_content = self.text_content + "!" + "\n";
};
this.ws.onmessage = function (event) {
//self.text_content = event.data + "\n";
var messageBody = JSON.parse(event.data);
Notification.info({
title: "通知",
dangerouslyUseHTMLString: true,
message: messageBody.noticeContent,
duration: 0,
offset: 40,
onClick: function () {
//self.warnDetailByWarnid(messageBody.warnId); //,message
//
},
});
};
this.ws.onclose = function (event) {
//self.text_content = self.text_content + "!" + "\n";
};
/** 消息推送 */
},
methods: {
/** 消息推送 */
notice() {
getNoticeListTop3().then(response => {
for (let i = 0; i < response.length; i++) {
let messageBody = response[i];
setTimeout(() => {
this.notificationInfo(messageBody);
}, 100);
}
})
},
notificationInfo(messageBody) {
Notification.info({
title: "通知",
dangerouslyUseHTMLString: true,
message: messageBody.noticeContent,
duration: 0,
offset: 40,
onClick: function () {
//self.warnDetailByWarnid(messageBody.warnId); //,message
//
},
});
},
// join() {
//
// },
exit() {
if (this.ws) {
this.ws.close();
this.ws = null;
}
},
send() {
if (this.ws) {
this.ws.send(this.message);
} else {
alert("未连接到服务器");
}
},
warnDetailByWarnid(warnid) {
//
this.$router.push({
path: "/XXX/XXX",
query: {
warnid: warnid,
},
});
},
/** 消息推送 */
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},

View File

@ -0,0 +1,175 @@
<template>
<!--1通知 2公告-->
<el-dropdown>
<span class="el-dropdown-link">
<svg-icon icon-class="message" slot="reference" />
<el-badge :value="noteTotal"></el-badge>
</span>
<el-dropdown-menu slot="dropdown">
<el-tabs v-model="activeName" @tab-click="handleClick" style="width:100%">
<el-tab-pane label="系统通知" name="first">
<el-dropdown-item v-for="(item,index) in noticeData" :key="index" >
<el-link :underline="false" @click="clickNote(item)" :style="index==0?'': 'margin-top :15px'">{{item.noticeTitle}}</el-link>
</el-dropdown-item>
<el-link :underline="false" style="margin-top :15px" v-if="noticeData.length>5" type="primary">更多消息</el-link>
</el-tab-pane>
<el-tab-pane label="系统公告" name="second">
<el-dropdown-item v-for="(item,index) in sysLog" :key="index">
<el-link :underline="false" @click="clickNote(item)" :style="index==0?'': 'margin-top :15px'">{{item.noticeTitle}}</el-link>
</el-dropdown-item>
<el-link v-if="sysLog.length>5" type="primary">更多消息</el-link>
</el-tab-pane>
</el-tabs>
</el-dropdown-menu>
<!--<mode-dialog :visible="noteVisible" :noteType="noteType" :noticeId="noticeId" @close="closeMode"></mode-dialog>-->
</el-dropdown>
</template>
<script>
import { navbarNoticelist } from '@/api/system/notice'
/*
import ModeDialog from '@/components/ModeDialog'
*/
export default {
name: 'NavbarNotice',
/*
components: { ModeDialog },
*/
data() {
return {
activeName: 'first',
//
queryParams: {
pageNum: 1,
pageSize: 5,
readFlag: '0'
},
noteTotal: '',
//
sysLog: [],
//
noticeData: [],
websock: null,
lockReconnect: false,
heartCheck: null,
noteVisible: false,
noteType: 0,
noticeId: 0
}
},
mounted() {
// WebSocket
this.initWebSocket()
},
destroyed: function() { //
this.websocketOnclose()
},
methods: {
getList() {
this.noticeData = []
this.sysLog = []
navbarNoticelist(this.queryParams).then(res => {
console.log(res[1])
this.noticeData = res[1]?res[1]:[];
this.sysLog = res[2]?res[2]:[];
this.noteTotal = this.noticeData.length+this.sysLog.length;
})
},
handleClick(tab, event) {
},
clickNote(data) {
this.noteVisible = true
this.noticeId = data.noticeId
this.noteType = data.noticeType == '1' ? 0 : 1
},
closeMode() {
this.getList()
this.noteVisible = false
},
initWebSocket() {
var userId = this.$store.getters.userId
// WebSocketwshttpwsshttps
// VUE_APP_BASE_API_WS = 'ws://localhost:9696'
var url = 'ws://localhost:3334/websocket/message';
this.websock = new WebSocket(url)
this.websock.onopen = this.websocketOnopen
this.websock.onerror = this.websocketOnerror
this.websock.onmessage = this.websocketOnmessage
this.websock.onclose = this.websocketOnclose
},
websocketOnopen: function() {
console.log('WebSocket连接成功')
},
websocketOnerror: function(e) {
console.log('WebSocket连接发生错误第%s次', this.wsConnectErrorTime)
this.wsConnectErrorTime = this.wsConnectErrorTime + 1
if (this.wsConnectErrorTime > 5) {
console.log('WebSocket连接错误超过5次就不再重新连了')
this.lockReconnect = true
return
}
this.reconnect()
},
websocketOnmessage: function(e) {
console.log('-----接收消息-------', e.data)
this.getList()
},
websocketOnclose: function(e) {
console.log('connection closed (' + e + ')')
if (e) {
console.log('connection closed (' + e.code + ')')
}
this.reconnect()
},
reconnect() {
var that = this
if (that.lockReconnect) return
that.lockReconnect = true
//
setTimeout(function() {
console.info('尝试重连...')
that.initWebSocket()
that.lockReconnect = false
}, 2000)
}
}
}
</script>
<style lang="scss" scoped>
.text-overflow {
width: 160px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 2px 0;
}
::v-deep .el-badge {
top: -7px;
}
::v-deep .el-badge__content.is-dot {
position: relative;
width: 11px;
height: 11px;
}
.el-tab-pane{
width:300px
}
.el-dropdown-menu{
width:250px
}
::v-deep .el-dropdown-menu {
top: 28px;
}
::v-deep .el-tabs {
padding: 12px;
width: 188px;
}
</style>