新增系统通知实时通知给连接的客户端

This commit is contained in:
不做码农 2022-03-01 14:04:21 +08:00
parent 06b81d5f5e
commit 267469dc55
11 changed files with 148 additions and 38 deletions

View File

@ -1,8 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Infrastructure;
using Infrastructure.Attribute;
using Infrastructure.Enums;
@ -15,6 +12,9 @@ using ZR.Common;
using ZR.Model.Dto;
using ZR.Model.Models;
using ZR.Service.System.IService;
using ZR.Admin.WebApi.Hubs;
using Microsoft.AspNetCore.SignalR;
using Infrastructure.Constant;
namespace ZR.Admin.WebApi.Controllers.System
{
@ -26,10 +26,12 @@ namespace ZR.Admin.WebApi.Controllers.System
/// 通知公告表接口
/// </summary>
private readonly ISysNoticeService _SysNoticeService;
private readonly IHubContext<MessageHub> _hubContext;
public SysNoticeController(ISysNoticeService SysNoticeService)
public SysNoticeController(ISysNoticeService SysNoticeService, IHubContext<MessageHub> hubContext)
{
_SysNoticeService = SysNoticeService;
_hubContext = hubContext;
}
/// <summary>
@ -96,11 +98,11 @@ namespace ZR.Admin.WebApi.Controllers.System
throw new CustomException("请求参数错误");
}
//从 Dto 映射到 实体
var model = parm.Adapt<SysNotice>().ToCreate(HttpContext);
model.Create_by = User.Identity.Name;
model.Create_time = DateTime.Now;
var modal = parm.Adapt<SysNotice>().ToCreate(HttpContext);
modal.Create_by = User.Identity.Name;
modal.Create_time = DateTime.Now;
return SUCCESS(_SysNoticeService.Insert(model, it => new
int result = _SysNoticeService.Insert(modal, it => new
{
it.NoticeTitle,
it.NoticeType,
@ -109,7 +111,9 @@ namespace ZR.Admin.WebApi.Controllers.System
it.Remark,
it.Create_by,
it.Create_time
}));
});
return SUCCESS(result);
}
/// <summary>
@ -142,6 +146,26 @@ namespace ZR.Admin.WebApi.Controllers.System
return SUCCESS(response);
}
/// <summary>
/// 发送通知公告表
/// </summary>
/// <returns></returns>
[HttpPut("send/{NoticeId}")]
[ActionPermissionFilter(Permission = "system:notice:update")]
[Log(Title = "通知公告表", BusinessType = BusinessType.OTHER)]
public IActionResult SendNotice(int NoticeId = 0)
{
if (NoticeId <= 0)
{
throw new CustomException("请求实体不能为空");
}
var response = _SysNoticeService.GetFirst(x => x.NoticeId == NoticeId);
if (response != null && response.Status == "0")
{
_hubContext.Clients.All.SendAsync(HubsConstant.ReceiveNotice, response.NoticeTitle, response.NoticeContent);
}
return SUCCESS(response);
}
/// <summary>
/// 删除通知公告表

View File

@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Infrastructure.Constant;
using Infrastructure.Model;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using ZR.Admin.WebApi.Filters;
using ZR.Model;
using ZR.Service.System.IService;
namespace ZR.Admin.WebApi.Hubs
{
@ -15,6 +14,20 @@ namespace ZR.Admin.WebApi.Hubs
{
//创建用户集合,用于存储所有链接的用户数据
private static readonly List<OnlineUsers> clientUsers = new();
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private ISysNoticeService SysNoticeService;
public MessageHub(ISysNoticeService noticeService)
{
SysNoticeService = noticeService;
}
private ApiResult SendNotice()
{
var result = SysNoticeService.GetSysNotices();
return new ApiResult(200, "success", result);
}
#region
@ -25,16 +38,18 @@ namespace ZR.Admin.WebApi.Hubs
public override Task OnConnectedAsync()
{
var name = Context.User.Identity.Name;
var user = clientUsers.Any(u => u.ConnnectionId == Context.ConnectionId);
//判断用户是否存在,否则添加集合
if (!user && Context.User.Identity.IsAuthenticated)
{
clientUsers.Add(new OnlineUsers(Context.ConnectionId, name));
Console.WriteLine($"{DateTime.Now}{name},{Context.ConnectionId}连接服务端success当前已连接{clientUsers.Count}个");
Clients.All.SendAsync("welcome", $"欢迎您:{name},当前时间:{DateTime.Now}");
Clients.All.SendAsync(HubsConstant.MoreNotice, SendNotice());
}
Clients.All.SendAsync("onlineNum", clientUsers.Count);
Clients.All.SendAsync(HubsConstant.OnlineNum, clientUsers.Count);
return base.OnConnectedAsync();
}
@ -50,7 +65,7 @@ namespace ZR.Admin.WebApi.Hubs
{
Console.WriteLine($"用户{user?.Name}离开了,当前已连接{clientUsers.Count}个");
clientUsers.Remove(user);
Clients.All.SendAsync("onlineNum", clientUsers.Count);
Clients.All.SendAsync(HubsConstant.OnlineNum, clientUsers.Count);
}
return base.OnDisconnectedAsync(exception);
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using ZR.Model.Models;
namespace ZR.Service.System.IService
@ -11,5 +12,6 @@ namespace ZR.Service.System.IService
/// </summary>
public interface ISysNoticeService: IBaseService<SysNotice>
{
List<SysNotice> GetSysNotices();
}
}

View File

@ -1,5 +1,7 @@
using Infrastructure;
using Infrastructure.Attribute;
using SqlSugar;
using System.Collections.Generic;
using ZR.Model.Models;
using ZR.Repository;
using ZR.Repository.System;
@ -24,6 +26,20 @@ namespace ZR.Service.System
#region
/// <summary>
/// 查询系统通知
/// </summary>
/// <returns></returns>
public List<SysNotice> GetSysNotices()
{
//开始拼装查询条件
var predicate = Expressionable.Create<SysNotice>();
//搜索条件查询语法参考Sqlsugar
predicate = predicate.And(m => m.Status == "0");
return _SysNoticerepository.GetList(predicate.ToExpression());
}
#endregion
}
}

View File

@ -50,4 +50,12 @@ export function delNotice(noticeId) {
url: '/system/notice/' + noticeId,
method: 'delete'
})
}
// 发送通知公告
export function sendNotice(noticeId) {
return request({
url: '/system/notice/send/' + noticeId,
method: 'PUT'
})
}

View File

@ -2,11 +2,11 @@
<div class="layout-navbars-breadcrumb-user-news">
<div class="head-box">
<div class="head-box-title">通知</div>
<div class="head-box-btn" v-if="dataList.length > 0" @click="onAllReadClick">全部已读</div>
<!-- <div class="head-box-btn" v-if="noticeList.length > 0" @click="onAllReadClick">全部已读</div> -->
</div>
<div class="content-box">
<template v-if="dataList.length > 0">
<div class="content-box-item" v-for="(v, k) in dataList" :key="k">
<template v-if="noticeList.length > 0">
<div class="content-box-item" v-for="(v, k) in noticeList" :key="k">
<div>{{ v.noticeTitle }}</div>
<div class="content-box-msg" v-html="v.noticeContent"></div>
<div class="content-box-time">{{ v.updateTime }}</div>
@ -19,12 +19,12 @@
</div>
</div>
</div>
<div class="foot-box" @click="onGoToGiteeClick" v-if="dataList.length > 0">前往通知中心</div>
<div class="foot-box" @click="onGoToGiteeClick" v-if="noticeList.length > 0">前往通知中心</div>
</div>
</template>
<script>
import { queryNotice } from "@/api/system/notice";
import { mapGetters } from "vuex";
export default {
name: "noticeIndex",
data() {
@ -32,15 +32,15 @@ export default {
dataList: [],
};
},
computed: {
...mapGetters(['noticeList'])
},
mounted() {
queryNotice().then((res) => {
this.dataList = res.data.result;
});
},
methods: {
//
onAllReadClick() {
this.dataList = [];
},
//
onGoToGiteeClick() {

View File

@ -44,9 +44,6 @@ Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree
signalR.init(process.env.VUE_APP_SOCKET_API);
Vue.prototype.signalr = signalR
Vue.prototype.msgSuccess = function (msg) {
this.$message({ showClose: true, message: msg, type: "success" });
}
@ -75,6 +72,9 @@ Vue.use(Element, {
Vue.config.productionTip = false
signalR.init(process.env.VUE_APP_SOCKET_API);
Vue.prototype.signalr = signalR
new Vue({
el: '#app',
router,

View File

@ -16,6 +16,7 @@ const getters = {
topbarRouters: state => state.permission.topbarRouters,
defaultRoutes: state => state.permission.defaultRoutes,
sidebarRouters: state => state.permission.sidebarRouters,
onlineUserNum: state => state.socket.onlineNum
onlineUserNum: state => state.socket.onlineNum,
noticeList: state => state.socket.noticeList
}
export default getters

View File

@ -1,10 +1,14 @@
const state = {
onlineNum: 0
onlineNum: 0,
noticeList: []
}
const mutations = {
SET_ONLINEUSER_NUM: (state, num) => {
state.onlineNum = num
},
SET_NOTICE_list: (state, data) => {
state.noticeList = data;
}
}
const actions = {
@ -12,6 +16,10 @@ const actions = {
changeOnlineNum({ commit }, data) {
commit('SET_ONLINEUSER_NUM', data)
},
// 更新系统通知
getNoticeList({ commit }, data) {
commit('SET_NOTICE_list', data)
}
}
export default {

View File

@ -2,6 +2,7 @@
import * as signalR from '@microsoft/signalr'
import store from '../store'
import { getToken } from '@/utils/auth'
import { Notification } from 'element-ui'
export default {
// signalR对象
@ -14,19 +15,16 @@ export default {
.withUrl(url, { accessTokenFactory: () => getToken() })
.build();
this.SR = connection;
// 断线重连
connection.onclose(async () => {
console.log('断开连接了')
console.log('断开连接了')
await this.start();
})
connection.onreconnected(() => {
console.log('断线重连')
})
connection.on("onlineNum", (data) => {
store.dispatch("socket/changeOnlineNum", data);
});
this.receiveMsg(connection);
// 启动
// this.start();
},
@ -49,5 +47,32 @@ export default {
}, 5000);
}
}
},
// 接收消息处理
receiveMsg(connection) {
connection.on("onlineNum", (data) => {
store.dispatch("socket/changeOnlineNum", data);
});
// 接收欢迎语
connection.on("welcome", (data) => {
console.log('welcome', data)
Notification.info(data)
});
// 接收后台手动推送消息
connection.on("receiveNotice", (title, data) => {
Notification({
type: 'info',
title: title,
message: data,
dangerouslyUseHTMLString: true,
duration: 0
})
})
// 接收系统通知/公告
connection.on("moreNotice", (data) => {
if (data.code == 200) {
store.dispatch("socket/getNoticeList", data.data);
}
})
}
}

View File

@ -23,11 +23,13 @@
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:notice:edit']">修改
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:notice:edit']">
修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:notice:remove']">删除
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
v-hasPermi="['system:notice:remove']">删除
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@ -37,7 +39,7 @@
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="noticeId" width="100" />
<el-table-column label="公告标题" align="center" prop="noticeTitle" :show-overflow-tooltip="true" />
<el-table-column label="内容" align="center" prop="noticeContent" :show-overflow-tooltip="true" />
<el-table-column label="内容" align="center" prop="noticeContent" :show-overflow-tooltip="true" />
<el-table-column label="公告类型" align="center" prop="noticeType" width="100">
<template slot-scope="scope">
<dict-tag :options="typeOptions" :value="scope.row.noticeType" />
@ -56,6 +58,7 @@
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-bell" @click="handleNotice(scope.row)" v-hasPermi="['system:notice:edit']">通知</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:notice:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:notice:remove']">删除
</el-button>
@ -110,6 +113,7 @@ import {
delNotice,
addNotice,
updateNotice,
sendNotice,
// exportNotice,
} from "@/api/system/notice";
@ -226,6 +230,13 @@ export default {
this.open = true;
this.title = "修改公告";
});
},
//
handleNotice(row) {
const noticeId = row.noticeId || this.ids;
sendNotice(noticeId).then(res => {
this.msgSuccess("发送通知成功");
});
},
/** 提交按钮 */
submitForm: function () {