using JNPF.Common.Core.Handlers; using JNPF.Common.Core.Manager; using JNPF.Common.Enums; using JNPF.Common.Extension; using JNPF.Common.Filter; using JNPF.Common.Options; using JNPF.Common.Security; using JNPF.DatabaseAccessor; using JNPF.DependencyInjection; using JNPF.DynamicApiController; using JNPF.FriendlyException; using JNPF.LinqBuilder; using JNPF.Message.Entitys; using JNPF.Message.Entitys.Dto.Message; using JNPF.Message.Entitys.Entity; using JNPF.Message.Interfaces.Message; using JNPF.RemoteRequest.Extensions; using JNPF.Systems.Entitys.Permission; using JNPF.Systems.Interfaces.Permission; using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; namespace JNPF.Message; /// /// 系统消息 /// 版 本:V3.2 /// 版 权:引迈信息技术有限公司(https://www.jnpfsoft.com) /// 作 者:JNPF开发平台组 /// 日 期:2021-06-01. /// [ApiDescriptionSettings(Tag = "Message", Name = "message", Order = 240)] [Route("api/[controller]")] public class MessageService : IMessageService, IDynamicApiController, ITransient { private readonly ISqlSugarRepository _repository; private readonly MessageOptions _messageOptions = App.GetConfig("Message", true); private readonly IMHandler _imHandler; /// /// 用户服务. /// private readonly IUsersService _usersService; /// /// 用户服务. /// private readonly IUserRelationService _userRelationService; /// /// 用户管理. /// private readonly IUserManager _userManager; /// /// 初始化一个类型的新实例. /// public MessageService( ISqlSugarRepository repository, IUsersService usersService, IUserRelationService userRelationService, IUserManager userManager, IMHandler imHandler) { _repository = repository; _usersService = usersService; _userRelationService = userRelationService; _userManager = userManager; _imHandler = imHandler; } #region Get /// /// 列表(通知公告). /// /// 请求参数. /// [HttpGet("Notice")] public async Task GetNoticeList([FromQuery] PageInputBase input) { var list = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, b.Id == a.LastModifyUserId)) .Where(a => a.Type == 1 && a.DeleteMark == null) .WhereIF(!string.IsNullOrEmpty(input.keyword), a => a.Title.Contains(input.keyword)) .OrderBy(a => a.EnabledMark).OrderBy(a => a.CreatorTime, OrderByType.Desc) .OrderBy(a => a.LastModifyTime, OrderByType.Desc) .Select((a, b) => new MessageNoticeOutput { id = a.Id, releaseTime = a.LastModifyTime, enabledMark = a.EnabledMark, releaseUser = SqlFunc.MergeString(b.RealName, "/", b.Account), title = a.Title, type = a.Type, creatorTime = a.CreatorTime, }).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } /// /// 列表(通知公告/系统消息/私信消息). /// /// 请求参数. /// [HttpGet("")] public async Task GetMessageList([FromQuery] MessageListQueryInput input) { var list = await _repository.AsSugarClient().Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, a.Id == b.MessageId, JoinType.Left, a.CreatorUserId == c.Id)) .Where((a, b) => b.UserId == _userManager.UserId && a.DeleteMark == null) .WhereIF(input.type.IsNotEmptyOrNull(), a => a.Type == input.type) .WhereIF(input.isRead.IsNotEmptyOrNull(), (a, b) => b.IsRead == SqlFunc.ToInt32(input.isRead)) .WhereIF(input.keyword.IsNotEmptyOrNull(), a => a.Title.Contains(input.keyword)) .OrderBy(a => a.LastModifyTime, OrderByType.Desc) .Select((a, b, c) => new MessageListOutput { id = a.Id, releaseTime = a.LastModifyTime, releaseUser = SqlFunc.MergeString(c.RealName, "/", c.Account), title = a.Title, type = a.Type, isRead = b.IsRead, flowType = a.FlowType }).ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(list); } /// /// 信息. /// /// 主键值. /// [HttpGet("{id}")] public async Task GetInfo_Api(string id) { return await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.CreatorUserId == b.Id)) .Where(a => a.Id == id && a.DeleteMark == null) .Select((a, b) => new MessageInfoOutput { id = a.Id, releaseTime = a.LastModifyTime, releaseUser = SqlFunc.MergeString(b.RealName, "/", b.Account), title = a.Title, bodyText = a.BodyText, files = a.Files, toUserIds = a.ToUserIds, }).FirstAsync(); } /// /// 读取消息. /// /// 主键值. /// [HttpGet("ReadInfo/{id}")] public async Task ReadInfo(string id) { var data = await _repository.AsSugarClient().Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, a.CreatorUserId == b.Id, JoinType.Left, a.Id == c.MessageId)) .Where((a, b, c) => a.Id == id && a.DeleteMark == null && c.UserId == _userManager.UserId) .OrderBy(a => a.LastModifyTime) .Select((a, b, c) => new MessageReadInfoOutput { id = a.Id, releaseTime = a.LastModifyTime, releaseUser = SqlFunc.MergeString(b.RealName, "/", b.Account), title = a.Title, bodyText = c.BodyText, files = a.Files }).FirstAsync(); if (data != null) await MessageRead(id, null, null, null); return data; } /// /// 读取消息. /// /// 主键值. /// [HttpGet("getUnReadMsgNum")] public async Task GetUnReadMsgNum() { var unReadMsg = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.MessageId)).Where((a, b) => a.Type == 2 && b.UserId == _userManager.UserId && b.IsRead == 0).CountAsync(); var unReadNotice = await _repository.AsSugarClient().Queryable((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.MessageId)).Where((a, b) => a.Type == 1 && b.UserId == _userManager.UserId && b.IsRead == 0).CountAsync(); return new { unReadMsg = unReadMsg, unReadNotice = unReadNotice, unReadNum = unReadMsg + unReadNotice }; } #endregion #region Post /// /// 删除. /// /// 主键值. /// [HttpDelete("{id}")] [UnitOfWork] public async Task Delete(string id) { try { await _repository.AsSugarClient().Deleteable().Where(x => x.MessageId == id).ExecuteCommandAsync(); await _repository.AsUpdateable().SetColumns(it => new MessageEntity() { DeleteMark = 1, DeleteUserId = _userManager.UserId, DeleteTime = SqlFunc.GetDate() }).Where(it => it.Id.Equals(id)).ExecuteCommandAsync(); } catch (Exception) { throw Oops.Oh(ErrorCode.COM1002); } } /// /// 新建. /// /// 实体对象. /// [HttpPost("")] public async Task Create([FromBody] MessageCrInput input) { var entity = input.Adapt(); entity.Type = 1; entity.EnabledMark = 0; var isOk = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync(); if (isOk < 1) throw Oops.Oh(ErrorCode.COM1000); } /// /// 更新. /// /// 主键值 /// 实体对象 /// [HttpPut("{id}")] public async Task Update(string id, [FromBody] MessageUpInput input) { var entity = input.Adapt(); var isOk = await _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync(); if (!isOk) throw Oops.Oh(ErrorCode.COM1001); } /// /// 发布公告. /// /// 主键值. /// [HttpPut("{id}/Actions/Release")] public async Task Release(string id) { var entity = await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null); if (entity != null) { // 发送 await SentNotice(entity); } } /// /// 全部已读. /// /// [HttpPost("Actions/ReadAll")] public async Task AllRead([FromQuery] string isRead, [FromQuery] string keyword, [FromQuery] string type) { await MessageRead(string.Empty, isRead, keyword, type); } /// /// 删除记录. /// /// 请求参数. /// [HttpDelete("Record")] public async Task DeleteRecord_Api([FromBody] dynamic postParam) { string[] ids = postParam.ids.ToString().Split(','); var isOk = await _repository.AsSugarClient().Deleteable().Where(m => m.UserId == _userManager.UserId && ids.Contains(m.MessageId)).ExecuteCommandHasChangeAsync(); if (!isOk) throw Oops.Oh(ErrorCode.COM1002); } #endregion #region PublicMethod /// /// 创建. /// /// 实体对象. /// 收件用户. [NonAction] private int Create(MessageEntity entity, List receiveEntityList) { try { //modify ly on 20230803 改为CopyNew模式,否则多线程下会报错 _repository.AsSugarClient().CopyNew().Insertable(receiveEntityList).ExecuteCommand(); return _repository.AsSugarClient().CopyNew().Insertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteCommand(); } catch (Exception) { return 0; } } /// /// 更新. /// /// 实体对象. /// 收件用户. [NonAction] private int Update(MessageEntity entity, List receiveEntityList) { try { _repository.AsSugarClient().Insertable(receiveEntityList).ExecuteCommand(); return _repository.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommand(); } catch (Exception) { return 0; } } /// /// 消息已读(全部). /// /// id. [NonAction] private async Task MessageRead(string id, string isRead, string keyword, string type) { var ids = await _repository.AsSugarClient().Queryable((a, b, c) => new JoinQueryInfos(JoinType.Left, a.Id == b.MessageId, JoinType.Left, a.CreatorUserId == c.Id)) .Where((a, b) => b.UserId == _userManager.UserId && a.DeleteMark == null) .WhereIF(id.IsNotEmptyOrNull(), a => a.Id == id) .WhereIF(type.IsNotEmptyOrNull(), a => a.Type == SqlFunc.ToInt32(type)) .WhereIF(!string.IsNullOrEmpty(isRead), a => a.IsRead == SqlFunc.ToInt32(isRead)) .WhereIF(!string.IsNullOrEmpty(keyword), a => a.Title.Contains(keyword)) .Select((a, b, c) => a.Id).ToListAsync(); if (!_repository.AsSugarClient().Queryable().Any(x => x.IsRead == 0 && x.UserId == _userManager.UserId) && id.IsNullOrEmpty()) { throw Oops.Oh(ErrorCode.D7017); } await _repository.AsSugarClient().Updateable().SetColumns(it => it.ReadCount == it.ReadCount + 1).SetColumns(x => new MessageReceiveEntity() { IsRead = 1, ReadTime = DateTime.Now }).Where(x => ids.Contains(x.MessageId)).ExecuteCommandAsync(); } /// /// 发送公告. /// /// 消息信息. [NonAction] private async Task SentNotice(MessageEntity entity) { try { var toUserIds = new List(); entity.EnabledMark = 1; if (entity.ToUserIds.IsNullOrEmpty()) toUserIds = (await _usersService.GetList()).Select(x => x.Id).ToList(); else toUserIds = await _userRelationService.GetUserId(entity.ToUserIds.Split(",").ToList()); List receiveEntityList = toUserIds .Select(x => new MessageReceiveEntity() { Id = SnowflakeIdHelper.NextId(), MessageId = entity.Id, UserId = x, IsRead = 0, BodyText = entity.BodyText, }).ToList(); Update(entity, receiveEntityList); if (entity.ToUserIds.IsNullOrEmpty()) { await _imHandler.SendMessageToTenantAsync(_userManager.TenantId, new { method = "messagePush", messageType = 1, userId = _userManager.UserId, toUserId = toUserIds, title = entity.Title, unreadNoticeCount = 1, id = entity.Id }.ToJsonString()); } else { foreach (var item in toUserIds) { var userId = item.Replace("-delegate", string.Empty); // 消息推送 - 指定用户 await _imHandler.SendMessageToUserAsync(string.Format("{0}-{1}", _userManager.TenantId, userId), new { method = "messagePush", messageType = 2, userId = _userManager.UserId, toUserId = toUserIds, title = entity.Title, unreadNoticeCount = 1, id = entity.Id }.ToJsonString()); } } } catch (Exception ex) { throw Oops.Oh(ErrorCode.D7003); } } /// /// 发送站内消息. /// /// 发送用户. /// 标题. /// 内容. [NonAction] public async Task SentMessage(List toUserIds, string title, string bodyText = null, Dictionary bodyDic = null, int type = 2, string flowType = "1") { try { //modifyby zhoukeda 20230704 定时任务发起的推送消息没有user string userManagerUserId = _userManager.UserId ?? ""; string userManagerTenantId = _userManager.TenantId ?? ""; MessageEntity entity = new MessageEntity(); entity.Id = SnowflakeIdHelper.NextId(); entity.Title = title; entity.BodyText = bodyText; entity.Type = type; entity.LastModifyTime = DateTime.Now; entity.LastModifyUserId = userManagerUserId; entity.FlowType = flowType.ParseToInt(); List receiveEntityList = toUserIds .Select(x => new MessageReceiveEntity() { Id = SnowflakeIdHelper.NextId(), MessageId = entity.Id, UserId = x.Replace("-delegate", string.Empty), IsRead = 0, BodyText = bodyDic.IsNotEmptyOrNull() && bodyDic.ContainsKey(x) ? bodyDic[x].ToJsonString() : null, }).ToList(); if (Create(entity, receiveEntityList) >= 1) { foreach (var item in toUserIds) { var userId = item.Replace("-delegate", string.Empty); // 消息推送 - 指定用户 await _imHandler.SendMessageToUserAsync(string.Format("{0}-{1}", userManagerTenantId, userId), new { method = "messagePush", messageType = 2, userId = userManagerUserId, toUserId = toUserIds, title = entity.Title, unreadNoticeCount = 1, id = entity.Id }.ToJsonString()); } } } catch (Exception ex) { throw; } } /// /// 发送个推. /// /// 推送用户. /// 标题. /// 内容. /// 消息id. /// 1:公告消息、2:流程消息、3:聊天消息. /// private async Task GeTuiMessage(List toUserIds, string title, string content, string msgId, string type) { var getuiUrl = "{0}?clientId={1}&title={2}&content={3}1&text={4}&create=true"; if (toUserIds.Any()) { var clientIdList = await _repository.AsSugarClient().Queryable().Where(x => toUserIds.Contains(x.UserId) && x.DeleteMark == null).Select(x => x.ClientId).ToListAsync(); if (clientIdList.Any()) { var clientId = string.Join(",", clientIdList); var textDic = new Dictionary(); textDic.Add("type", type); if (type == "3") { var userName = await _usersService.GetUserName(_userManager.UserId); textDic.Add("name", userName); textDic.Add("formUserId", _userManager.UserId); textDic.Add("headIcon", "/api/File/Image/userAvatar/" + _userManager.User.HeadIcon); } else { textDic.Add("id", msgId); textDic.Add("title", title); } getuiUrl = string.Format(getuiUrl, _messageOptions.AppPushUrl, clientId, title, content, textDic.ToJsonString()); await getuiUrl.GetAsStringAsync(); } } } #endregion }