feat: 新增消息通知模块
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
using Yi.Framework.Ddd.Application.Contracts;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Notice
|
||||||
|
{
|
||||||
|
public class BbsNoticeGetListInputVo:PagedAllResultRequestDto
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Notice
|
||||||
|
{
|
||||||
|
public class BbsNoticeGetListOutputDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 消息,支持html
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息类型
|
||||||
|
/// </summary>
|
||||||
|
public NoticeTypeEnum NoticeType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否已读
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRead { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已读时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ReadTime { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息创建时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime CreationTime { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using Mapster;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
using Volo.Abp.Application.Services;
|
||||||
|
using Yi.Framework.Bbs.Application.Contracts.Dtos.Notice;
|
||||||
|
using Yi.Framework.Bbs.Domain.Entities;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Application.Services
|
||||||
|
{
|
||||||
|
public class BbsNoticeService : ApplicationService
|
||||||
|
{
|
||||||
|
private ISqlSugarRepository<BbsNoticeAggregateRoot, Guid> _repository;
|
||||||
|
public BbsNoticeService(ISqlSugarRepository<BbsNoticeAggregateRoot, Guid> repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询用户的消息,需登录
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
|
[Authorize]
|
||||||
|
public async Task<PagedResultDto<BbsNoticeGetListOutputDto>> GetListAsync(BbsNoticeGetListInputVo input)
|
||||||
|
{
|
||||||
|
RefAsync<int> total = 0;
|
||||||
|
var entities = await _repository._DbQueryable.Where(x => x.AcceptUserId == CurrentUser.Id)
|
||||||
|
.OrderByDescending(x => x.CreationTime)
|
||||||
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
||||||
|
|
||||||
|
var output = entities.Adapt<List<BbsNoticeGetListOutputDto>>();
|
||||||
|
return new PagedResultDto<BbsNoticeGetListOutputDto>(total, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已读消息,不传guid,代表一键已读,需登录
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
[Authorize]
|
||||||
|
[Route("bbs-notice/read/{noticeId?}")]
|
||||||
|
public async Task PutReadAsync(Guid? noticeId)
|
||||||
|
{
|
||||||
|
//一键已读
|
||||||
|
if (noticeId is null)
|
||||||
|
{
|
||||||
|
await _repository._Db.Updateable<BbsNoticeAggregateRoot>()
|
||||||
|
.SetColumns(it => it.IsRead == true)
|
||||||
|
.Where(x => x.AcceptUserId == CurrentUser.Id)
|
||||||
|
.Where(x => x.IsRead == false)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
//已读一条
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _repository._Db.Updateable<BbsNoticeAggregateRoot>()
|
||||||
|
.SetColumns(it => it.IsRead == true)
|
||||||
|
.Where(x => x.AcceptUserId == CurrentUser.Id)
|
||||||
|
.Where(x => x.IsRead == false)
|
||||||
|
.Where(x => x.Id == noticeId)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,6 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
|||||||
/// Todo: 可放入领域层
|
/// Todo: 可放入领域层
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[UnitOfWork]
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<AgreeDto> PostOperateAsync(Guid discussId)
|
public async Task<AgreeDto> PostOperateAsync(Guid discussId)
|
||||||
{
|
{
|
||||||
@@ -53,9 +52,8 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
//点赞过,删除即可,修改总点赞数量
|
//点赞过,删除即可,修改总点赞数量
|
||||||
await _repository.DeleteByIdAsync(entity.Id);
|
await _repository.DeleteAsync(entity);
|
||||||
var discussEntity = await _discssRepository.GetByIdAsync(discussId);
|
var discussEntity = await _discssRepository.GetByIdAsync(discussId);
|
||||||
if (discussEntity is null)
|
if (discussEntity is null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,5 +15,9 @@ namespace Yi.Framework.Bbs.Domain.Shared.Consts
|
|||||||
public const string No_Exist = "传入的主题id不存在";
|
public const string No_Exist = "传入的主题id不存在";
|
||||||
|
|
||||||
public const string Privacy = "【私密】您无该主题权限,可联系作者申请开放";
|
public const string Privacy = "【私密】您无该主题权限,可联系作者申请开放";
|
||||||
|
|
||||||
|
public const string AgreeNotice = "您的主题[{0}]被[{1}]用户点赞!得到一致认可,发现宝藏内容!";
|
||||||
|
|
||||||
|
public const string CommentNotice = "您的主题[{0}]被[{1}]用户评论!评论内容:[{2}]。。。";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Domain.Shared.Model
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 消息通知存储用户信息
|
||||||
|
/// </summary>
|
||||||
|
public class HubUserModel
|
||||||
|
{
|
||||||
|
public HubUserModel(string connnectionId,Guid userId)
|
||||||
|
{
|
||||||
|
ConnnectionId = connnectionId;
|
||||||
|
UserId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 客户端连接Id
|
||||||
|
/// </summary>
|
||||||
|
public string? ConnnectionId { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 用户id
|
||||||
|
/// </summary>
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,10 @@ namespace Yi.Framework.Bbs.Domain.Entities
|
|||||||
[SugarTable("BbsNotice")]
|
[SugarTable("BbsNotice")]
|
||||||
public class BbsNoticeAggregateRoot : AggregateRoot<Guid>, IHasCreationTime
|
public class BbsNoticeAggregateRoot : AggregateRoot<Guid>, IHasCreationTime
|
||||||
{
|
{
|
||||||
|
public BbsNoticeAggregateRoot()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
public BbsNoticeAggregateRoot(NoticeTypeEnum noticeType, string message, Guid? acceptUserId = null)
|
public BbsNoticeAggregateRoot(NoticeTypeEnum noticeType, string message, Guid? acceptUserId = null)
|
||||||
{
|
{
|
||||||
this.NoticeType = noticeType;
|
this.NoticeType = noticeType;
|
||||||
@@ -47,7 +51,7 @@ namespace Yi.Framework.Bbs.Domain.Entities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime? ReadTime { get; private set; }
|
public DateTime? ReadTime { get; private set; }
|
||||||
|
|
||||||
public DateTime CreationTime { get; }
|
public DateTime CreationTime { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Domain.Entities.Events;
|
using Volo.Abp.Domain.Entities.Events;
|
||||||
using Volo.Abp.EventBus;
|
using Volo.Abp.EventBus;
|
||||||
|
using Volo.Abp.EventBus.Local;
|
||||||
using Yi.Framework.Bbs.Domain.Entities;
|
using Yi.Framework.Bbs.Domain.Entities;
|
||||||
using Yi.Framework.Bbs.Domain.Entities.Forum;
|
using Yi.Framework.Bbs.Domain.Entities.Forum;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Consts;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
|
using Yi.Framework.Rbac.Domain.Entities;
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
namespace Yi.Framework.Bbs.Domain.EventHandlers
|
namespace Yi.Framework.Bbs.Domain.EventHandlers
|
||||||
@@ -13,49 +17,70 @@ namespace Yi.Framework.Bbs.Domain.EventHandlers
|
|||||||
public class AgreeCreatedEventHandler : ILocalEventHandler<EntityCreatedEventData<AgreeEntity>>,
|
public class AgreeCreatedEventHandler : ILocalEventHandler<EntityCreatedEventData<AgreeEntity>>,
|
||||||
ITransientDependency
|
ITransientDependency
|
||||||
{
|
{
|
||||||
private ISqlSugarRepository<BbsUserExtraInfoEntity> _userRepository;
|
private ISqlSugarRepository<UserAggregateRoot> _userRepository;
|
||||||
|
private ISqlSugarRepository<BbsUserExtraInfoEntity> _userInfoRepository;
|
||||||
private ISqlSugarRepository<AgreeEntity> _agreeRepository;
|
private ISqlSugarRepository<AgreeEntity> _agreeRepository;
|
||||||
public AgreeCreatedEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> userRepository, ISqlSugarRepository<AgreeEntity> agreeRepository)
|
private ILocalEventBus _localEventBus;
|
||||||
|
public AgreeCreatedEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> userInfoRepository, ISqlSugarRepository<AgreeEntity> agreeRepository, ILocalEventBus localEventBus, ISqlSugarRepository<UserAggregateRoot> userRepository)
|
||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userInfoRepository = userInfoRepository;
|
||||||
_agreeRepository = agreeRepository;
|
_agreeRepository = agreeRepository;
|
||||||
|
_localEventBus = localEventBus;
|
||||||
|
_userRepository = userRepository;
|
||||||
}
|
}
|
||||||
public async Task HandleEventAsync(EntityCreatedEventData<AgreeEntity> eventData)
|
public async Task HandleEventAsync(EntityCreatedEventData<AgreeEntity> eventData)
|
||||||
{
|
{
|
||||||
var agreeEntity = eventData.Entity;
|
var agreeEntity = eventData.Entity;
|
||||||
var userId = await _agreeRepository._DbQueryable.LeftJoin<DiscussAggregateRoot>((agree, discuss) => agree.DiscussId == discuss.Id)
|
|
||||||
.Select((agree, discuss) => discuss.CreatorId).FirstAsync();
|
|
||||||
|
|
||||||
//给创建者发布数量+1
|
//查询主题的信息
|
||||||
await _userRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
var discussAndAgreeDto = await _agreeRepository._DbQueryable
|
||||||
|
.LeftJoin<DiscussAggregateRoot>((agree, discuss) => agree.DiscussId == discuss.Id)
|
||||||
|
.Select((agree, discuss) =>
|
||||||
|
new
|
||||||
|
{
|
||||||
|
DiscussTitle = discuss.Title,
|
||||||
|
DiscussCreatorId = discuss.CreatorId,
|
||||||
|
})
|
||||||
|
.FirstAsync();
|
||||||
|
|
||||||
|
//查询点赞者用户
|
||||||
|
var agreeUser = await _userRepository.GetFirstAsync(x => x.Id == agreeEntity.CreatorId);
|
||||||
|
|
||||||
|
//给创建者点赞数量+1
|
||||||
|
await _userInfoRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
||||||
.SetColumns(it => it.AgreeNumber == it.AgreeNumber + 1)
|
.SetColumns(it => it.AgreeNumber == it.AgreeNumber + 1)
|
||||||
.Where(it => it.UserId == userId)
|
.Where(it => it.UserId == discussAndAgreeDto.DiscussCreatorId)
|
||||||
.ExecuteCommandAsync();
|
.ExecuteCommandAsync();
|
||||||
|
|
||||||
|
//通知主题作者,有人点赞
|
||||||
|
await _localEventBus.PublishAsync(new BbsNoticeEventArgs(discussAndAgreeDto.DiscussCreatorId!.Value, string.Format(DiscussConst.AgreeNotice, discussAndAgreeDto.DiscussTitle, agreeUser.UserName)), false);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 取消点赞
|
/// 取消点赞
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AgreeDeletedEventHandler : ILocalEventHandler<EntityCreatedEventData<AgreeEntity>>,
|
public class AgreeDeletedEventHandler : ILocalEventHandler<EntityDeletedEventData<AgreeEntity>>,
|
||||||
ITransientDependency
|
ITransientDependency
|
||||||
{
|
{
|
||||||
private ISqlSugarRepository<BbsUserExtraInfoEntity> _userRepository;
|
private ISqlSugarRepository<BbsUserExtraInfoEntity> _userRepository;
|
||||||
private ISqlSugarRepository<AgreeEntity> _agreeRepository;
|
private ISqlSugarRepository<AgreeEntity> _agreeRepository;
|
||||||
public AgreeDeletedEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> userRepository, ISqlSugarRepository<AgreeEntity> agreeRepository)
|
private ILocalEventBus _localEventBus;
|
||||||
|
public AgreeDeletedEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> userRepository, ISqlSugarRepository<AgreeEntity> agreeRepository, ILocalEventBus localEventBus)
|
||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
_agreeRepository = agreeRepository;
|
_agreeRepository = agreeRepository;
|
||||||
|
_localEventBus = localEventBus;
|
||||||
}
|
}
|
||||||
public async Task HandleEventAsync(EntityCreatedEventData<AgreeEntity> eventData)
|
public async Task HandleEventAsync(EntityDeletedEventData<AgreeEntity> eventData)
|
||||||
{
|
{
|
||||||
var agreeEntity = eventData.Entity;
|
var agreeEntity = eventData.Entity;
|
||||||
var userId = await _agreeRepository._DbQueryable.LeftJoin<DiscussAggregateRoot>((agree, discuss) => agree.DiscussId == discuss.Id)
|
var userId = await _agreeRepository._DbQueryable.LeftJoin<DiscussAggregateRoot>((agree, discuss) => agree.DiscussId == discuss.Id)
|
||||||
.Select((agree, discuss) => discuss.CreatorId).FirstAsync();
|
.Select((agree, discuss) => discuss.CreatorId).FirstAsync();
|
||||||
|
|
||||||
//给创建者发布数量-1
|
//给创建者点赞数量-1
|
||||||
await _userRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
await _userRepository._Db.Updateable<BbsUserExtraInfoEntity>()
|
||||||
.SetColumns(it => it.DiscussNumber == it.DiscussNumber - 1)
|
.SetColumns(it => it.AgreeNumber == it.AgreeNumber - 1)
|
||||||
.Where(it => it.UserId == userId)
|
.Where(it => it.UserId == userId)
|
||||||
.ExecuteCommandAsync();
|
.ExecuteCommandAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
using Volo.Abp.DependencyInjection;
|
|
||||||
using Volo.Abp.Domain.Entities.Events;
|
|
||||||
using Volo.Abp.EventBus;
|
|
||||||
using Yi.Framework.Bbs.Domain.Entities;
|
|
||||||
|
|
||||||
namespace Yi.Framework.Bbs.Domain.EventHandlers
|
|
||||||
{
|
|
||||||
public class BbsNoticeCreatedEventHandler : ILocalEventHandler<EntityCreatedEventData<BbsNoticeAggregateRoot>>,
|
|
||||||
ITransientDependency
|
|
||||||
{
|
|
||||||
public Task HandleEventAsync(EntityCreatedEventData<BbsNoticeAggregateRoot> eventData)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using SqlSugar;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.EventBus;
|
||||||
|
using Yi.Framework.Bbs.Domain.Entities;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
|
using Yi.Framework.Bbs.Domain.SignalRHubs;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Domain.EventHandlers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// bbs消息推送处理
|
||||||
|
/// </summary>
|
||||||
|
public class BbsNoticeSendEventHandler : ILocalEventHandler<BbsNoticeEventArgs>,
|
||||||
|
ITransientDependency
|
||||||
|
{
|
||||||
|
private IHubContext<BbsNoticeHub> _hubContext;
|
||||||
|
private ISqlSugarRepository<BbsNoticeAggregateRoot, Guid> _repository;
|
||||||
|
public BbsNoticeSendEventHandler(IHubContext<BbsNoticeHub> hubContext, ISqlSugarRepository<BbsNoticeAggregateRoot, Guid> sugarRepository)
|
||||||
|
{
|
||||||
|
_hubContext = hubContext;
|
||||||
|
_repository = sugarRepository;
|
||||||
|
}
|
||||||
|
public async Task HandleEventAsync(BbsNoticeEventArgs eventData)
|
||||||
|
{
|
||||||
|
//离线存储
|
||||||
|
await _repository.InsertAsync(new BbsNoticeAggregateRoot(eventData.NoticeType, eventData.Message, eventData.AcceptUserId));
|
||||||
|
switch (eventData.NoticeType)
|
||||||
|
{
|
||||||
|
case Shared.Enums.NoticeTypeEnum.Personal:
|
||||||
|
if (BbsNoticeHub.HubUserModels.TryGetValue(eventData.AcceptUserId.ToString(), out var hubUserModel))
|
||||||
|
{
|
||||||
|
_hubContext.Clients.Client(hubUserModel.ConnnectionId).SendAsync(NoticeTypeEnum.Personal.ToString(), eventData.Message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Shared.Enums.NoticeTypeEnum.Broadcast:
|
||||||
|
_hubContext.Clients.All.SendAsync(NoticeTypeEnum.Broadcast.ToString(), eventData.Message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
using Volo.Abp.DependencyInjection;
|
using TencentCloud.Tbm.V20180129.Models;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.Domain.Entities.Events;
|
using Volo.Abp.Domain.Entities.Events;
|
||||||
using Volo.Abp.EventBus;
|
using Volo.Abp.EventBus;
|
||||||
|
using Volo.Abp.EventBus.Local;
|
||||||
using Yi.Framework.Bbs.Domain.Entities;
|
using Yi.Framework.Bbs.Domain.Entities;
|
||||||
using Yi.Framework.Bbs.Domain.Entities.Forum;
|
using Yi.Framework.Bbs.Domain.Entities.Forum;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Consts;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Etos;
|
||||||
|
using Yi.Framework.Rbac.Domain.Entities;
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
namespace Yi.Framework.Bbs.Domain.EventHandlers
|
namespace Yi.Framework.Bbs.Domain.EventHandlers
|
||||||
@@ -13,10 +18,14 @@ namespace Yi.Framework.Bbs.Domain.EventHandlers
|
|||||||
public class CommentCreatedEventHandler : ILocalEventHandler<EntityCreatedEventData<CommentAggregateRoot>>,
|
public class CommentCreatedEventHandler : ILocalEventHandler<EntityCreatedEventData<CommentAggregateRoot>>,
|
||||||
ITransientDependency
|
ITransientDependency
|
||||||
{
|
{
|
||||||
private ISqlSugarRepository<BbsUserExtraInfoEntity> _userRepository;
|
private ILocalEventBus _localEventBus;
|
||||||
public CommentCreatedEventHandler(ISqlSugarRepository<BbsUserExtraInfoEntity> userRepository)
|
private ISqlSugarRepository<DiscussAggregateRoot> _discussRepository;
|
||||||
|
private ISqlSugarRepository<UserAggregateRoot> _userRepository;
|
||||||
|
public CommentCreatedEventHandler(ILocalEventBus localEventBus, ISqlSugarRepository<DiscussAggregateRoot> discussRepository, ISqlSugarRepository<UserAggregateRoot> userRepository)
|
||||||
{
|
{
|
||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
|
_localEventBus = localEventBus;
|
||||||
|
_discussRepository = discussRepository;
|
||||||
}
|
}
|
||||||
public async Task HandleEventAsync(EntityCreatedEventData<CommentAggregateRoot> eventData)
|
public async Task HandleEventAsync(EntityCreatedEventData<CommentAggregateRoot> eventData)
|
||||||
{
|
{
|
||||||
@@ -27,6 +36,24 @@ namespace Yi.Framework.Bbs.Domain.EventHandlers
|
|||||||
.SetColumns(it => it.CommentNumber == it.CommentNumber + 1)
|
.SetColumns(it => it.CommentNumber == it.CommentNumber + 1)
|
||||||
.Where(it => it.UserId == commentEntity.CreatorId)
|
.Where(it => it.UserId == commentEntity.CreatorId)
|
||||||
.ExecuteCommandAsync();
|
.ExecuteCommandAsync();
|
||||||
|
var disucssDto = await _discussRepository._DbQueryable
|
||||||
|
.Where(x => x.Id == commentEntity.DiscussId)
|
||||||
|
.LeftJoin<UserAggregateRoot>((dicuss, user) => dicuss.CreatorId == user.Id)
|
||||||
|
.Select((dicuss, user) =>
|
||||||
|
new
|
||||||
|
{
|
||||||
|
DiscussId = user.Id,
|
||||||
|
DiscussTitle = dicuss.Title,
|
||||||
|
|
||||||
|
})
|
||||||
|
.FirstAsync();
|
||||||
|
|
||||||
|
var commentUser = await _userRepository.GetFirstAsync(x => x.Id == commentEntity.CreatorId);
|
||||||
|
|
||||||
|
//截取10个长度
|
||||||
|
var content = commentEntity.Content.Length >= 10 ? commentEntity.Content.Substring(0, 10) : commentEntity.Content;
|
||||||
|
//通知主题作者,有人评论
|
||||||
|
await _localEventBus.PublishAsync(new BbsNoticeEventArgs(disucssDto.DiscussId, string.Format(DiscussConst.CommentNotice, disucssDto.DiscussTitle, commentUser.UserName, content)), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Volo.Abp.AspNetCore.SignalR;
|
||||||
|
using Yi.Framework.Bbs.Domain.Shared.Model;
|
||||||
|
|
||||||
|
namespace Yi.Framework.Bbs.Domain.SignalRHubs
|
||||||
|
{
|
||||||
|
[HubRoute("/hub/bbs-notice")]
|
||||||
|
[Authorize]
|
||||||
|
public class BbsNoticeHub : AbpHub
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// hub连接与用户id的映射关系存储
|
||||||
|
/// </summary>
|
||||||
|
public static ConcurrentDictionary<string, HubUserModel> HubUserModels = new ConcurrentDictionary<string, HubUserModel>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接添加用户信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override Task OnConnectedAsync()
|
||||||
|
{
|
||||||
|
var hubUser = new HubUserModel(Context.ConnectionId, CurrentUser.Id!.Value);
|
||||||
|
HubUserModels.TryAdd(CurrentUser.Id.Value.ToString(), hubUser);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 断开连接,去除用户连接信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exception"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override Task OnDisconnectedAsync(Exception exception)
|
||||||
|
{
|
||||||
|
HubUserModels.TryRemove(CurrentUser.Id.Value.ToString(), out _);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Yi.Bbs.Vue3/package-lock.json
generated
14
Yi.Bbs.Vue3/package-lock.json
generated
@@ -12,7 +12,7 @@
|
|||||||
"@lucky-canvas/vue": "^0.1.11",
|
"@lucky-canvas/vue": "^0.1.11",
|
||||||
"@microsoft/signalr": "^8.0.0",
|
"@microsoft/signalr": "^8.0.0",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.11",
|
||||||
"echarts": "^5.4.2",
|
"echarts": "^5.4.2",
|
||||||
"element-plus": "^2.2.32",
|
"element-plus": "^2.2.32",
|
||||||
"highlight": "^0.2.4",
|
"highlight": "^0.2.4",
|
||||||
@@ -1894,9 +1894,9 @@
|
|||||||
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
|
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
|
||||||
},
|
},
|
||||||
"node_modules/dayjs": {
|
"node_modules/dayjs": {
|
||||||
"version": "1.11.10",
|
"version": "1.11.11",
|
||||||
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.10.tgz",
|
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.11.tgz",
|
||||||
"integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ=="
|
"integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg=="
|
||||||
},
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
@@ -5551,9 +5551,9 @@
|
|||||||
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
|
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
|
||||||
},
|
},
|
||||||
"dayjs": {
|
"dayjs": {
|
||||||
"version": "1.11.10",
|
"version": "1.11.11",
|
||||||
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.10.tgz",
|
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.11.tgz",
|
||||||
"integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ=="
|
"integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg=="
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"@lucky-canvas/vue": "^0.1.11",
|
"@lucky-canvas/vue": "^0.1.11",
|
||||||
"@microsoft/signalr": "^8.0.0",
|
"@microsoft/signalr": "^8.0.0",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.3.4",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.11",
|
||||||
"echarts": "^5.4.2",
|
"echarts": "^5.4.2",
|
||||||
"element-plus": "^2.2.32",
|
"element-plus": "^2.2.32",
|
||||||
"highlight": "^0.2.4",
|
"highlight": "^0.2.4",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import mainHub from "@/hubs/mainHub.js";
|
import mainHub from "@/hubs/mainHub.js";
|
||||||
import noticeSignalR from "@/hubs/noticeHub.js";
|
import noticeSignalR from "@/hubs/noticeHub.js";
|
||||||
|
import bbsNoticeSignalR from "@/hubs/bbsNoticeHub.js";
|
||||||
import useConfigStore from "@/stores/config";
|
import useConfigStore from "@/stores/config";
|
||||||
import { ElConfigProvider } from "element-plus";
|
import { ElConfigProvider } from "element-plus";
|
||||||
import useUserStore from "@/stores/user.js";
|
import useUserStore from "@/stores/user.js";
|
||||||
@@ -26,7 +27,12 @@ if (loading !== null) {
|
|||||||
//加载全局信息
|
//加载全局信息
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await configStore.getConfig();
|
await configStore.getConfig();
|
||||||
|
|
||||||
|
//如果登录了,再连接消息通知
|
||||||
|
bbsNoticeSignalR();
|
||||||
noticeSignalR();
|
noticeSignalR();
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|||||||
19
Yi.Bbs.Vue3/src/apis/bbsNoticeApi.js
Normal file
19
Yi.Bbs.Vue3/src/apis/bbsNoticeApi.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import request from "@/config/axios/service";
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: "/bbs-notice",
|
||||||
|
method: "get",
|
||||||
|
params: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function read(id) {
|
||||||
|
|
||||||
|
return request({
|
||||||
|
url: `/bbs-notice/read/${id??''}`,
|
||||||
|
method: "put"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
20
Yi.Bbs.Vue3/src/hubs/bbsNoticeHub.js
Normal file
20
Yi.Bbs.Vue3/src/hubs/bbsNoticeHub.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import signalR from "@/utils/signalR";
|
||||||
|
import useNoticeStore from "@/stores/notice";
|
||||||
|
import { dayjs } from 'element-plus'
|
||||||
|
const receiveMsg=(connection)=> {
|
||||||
|
|
||||||
|
const noticeStore = useNoticeStore();
|
||||||
|
connection.on("Personal", (message) => {
|
||||||
|
noticeStore.addNotice({
|
||||||
|
message:message,
|
||||||
|
isRead:false,
|
||||||
|
creationTime:dayjs().format()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ()=>{
|
||||||
|
signalR.start(`bbs-notice`,receiveMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -7,41 +7,30 @@
|
|||||||
<div class="text">{{ configStore.name }}</div>
|
<div class="text">{{ configStore.name }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab">
|
<div class="tab">
|
||||||
<el-menu
|
<el-menu :default-active="activeIndex" mode="horizontal" :ellipsis="false" @select="handleSelect">
|
||||||
:default-active="activeIndex"
|
|
||||||
mode="horizontal"
|
|
||||||
:ellipsis="false"
|
|
||||||
@select="handleSelect"
|
|
||||||
>
|
|
||||||
<el-menu-item index="1" @click="enterIndex">主页</el-menu-item>
|
<el-menu-item index="1" @click="enterIndex">主页</el-menu-item>
|
||||||
<el-sub-menu index="2">
|
<el-sub-menu index="2">
|
||||||
<template #title>学习</template>
|
<template #title>学习</template>
|
||||||
<el-menu-item index="2-1">学习 one</el-menu-item>
|
<el-menu-item index="2-1">前端</el-menu-item>
|
||||||
<el-menu-item index="2-2">学习 two</el-menu-item>
|
<el-menu-item index="2-2">后端</el-menu-item>
|
||||||
<el-menu-item index="2-3">学习 three</el-menu-item>
|
<el-menu-item index="2-3">运维</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-sub-menu index="3">
|
<el-sub-menu index="3">
|
||||||
<template #title>资源</template>
|
<template #title>资源</template>
|
||||||
<el-menu-item index="3-1">资源 one</el-menu-item>
|
<el-menu-item index="3-1">前端</el-menu-item>
|
||||||
<el-menu-item index="3-2">资源 two</el-menu-item>
|
<el-menu-item index="3-2">后端</el-menu-item>
|
||||||
<el-menu-item index="3-3">资源 three</el-menu-item>
|
<el-menu-item index="3-3">运维</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-sub-menu index="4">
|
<el-sub-menu index="4">
|
||||||
<template #title>问答</template>
|
<template #title>问答</template>
|
||||||
<el-menu-item index="4-1">问答 one</el-menu-item>
|
<el-menu-item index="4-1">前端</el-menu-item>
|
||||||
<el-menu-item index="4-2">问答 two</el-menu-item>
|
<el-menu-item index="4-2">后端</el-menu-item>
|
||||||
<el-menu-item index="4-3">问答 three</el-menu-item>
|
<el-menu-item index="4-3">运维</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="search-bar">
|
<div class="search-bar">
|
||||||
<el-input
|
<el-input style="width: 300px" v-model="searchText" placeholder="全站搜索" clearable prefix-icon="Search">
|
||||||
style="width: 300px"
|
|
||||||
v-model="searchText"
|
|
||||||
placeholder="全站搜索"
|
|
||||||
clearable
|
|
||||||
prefix-icon="Search"
|
|
||||||
>
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button type="primary" plain @click="search">搜索</el-button>
|
<el-button type="primary" plain @click="search">搜索</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -50,7 +39,7 @@
|
|||||||
<div class="user">
|
<div class="user">
|
||||||
|
|
||||||
|
|
||||||
<div class="money" v-if="isLogin">钱钱:<span>{{money}}</span></div>
|
<div class="money" v-if="isLogin">钱钱:<span>{{ money }}</span></div>
|
||||||
<el-dropdown trigger="click">
|
<el-dropdown trigger="click">
|
||||||
<AvatarInfo :size="30" :isSelf="true" />
|
<AvatarInfo :size="30" :isSelf="true" />
|
||||||
|
|
||||||
@@ -58,13 +47,9 @@
|
|||||||
|
|
||||||
|
|
||||||
<el-dropdown-menu v-if="isLogin">
|
<el-dropdown-menu v-if="isLogin">
|
||||||
<el-dropdown-item>你的钱钱:{{money}}</el-dropdown-item>
|
<el-dropdown-item>你的钱钱:{{ money }}</el-dropdown-item>
|
||||||
<el-dropdown-item @click="enterProfile"
|
<el-dropdown-item @click="enterProfile">进入个人中心</el-dropdown-item>
|
||||||
>进入个人中心</el-dropdown-item
|
<el-dropdown-item @click="enterActivity">进入活动页面</el-dropdown-item>
|
||||||
>
|
|
||||||
<el-dropdown-item @click="enterActivity"
|
|
||||||
>进入活动页面</el-dropdown-item
|
|
||||||
>
|
|
||||||
<el-dropdown-item @click="logout">登出</el-dropdown-item>
|
<el-dropdown-item @click="logout">登出</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
<el-dropdown-menu v-else>
|
<el-dropdown-menu v-else>
|
||||||
@@ -73,7 +58,42 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
|
||||||
|
<div class="notice">
|
||||||
|
<el-dropdown trigger="click" :max-height="500">
|
||||||
|
<el-badge :value="noticeStore.noticeForNoReadCount">
|
||||||
|
<el-button type="primary">
|
||||||
|
<el-icon :size="15">
|
||||||
|
<Bell />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-badge>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
|
||||||
|
<el-dropdown-item class="notice-oper" style="justify-content: space-between;">
|
||||||
|
<el-button type="primary" @click="fetchNoticeData">刷新</el-button>
|
||||||
|
<el-button type="warning" @click="hanldeReadClick">一键已读</el-button>
|
||||||
|
</el-dropdown-item>
|
||||||
|
|
||||||
|
|
||||||
|
<el-dropdown-item v-for="(item, index) in noticeList" :key="index">
|
||||||
|
<div v-if="item.isRead" class="notice-msg" v-html="item.message"></div>
|
||||||
|
|
||||||
|
<el-badge is-dot v-else >
|
||||||
|
<div class="notice-msg" v-html="item.message"></div>
|
||||||
|
</el-badge>
|
||||||
|
|
||||||
|
|
||||||
|
</el-dropdown-item>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="gitee" @click="handleGitClick">
|
<div class="gitee" @click="handleGitClick">
|
||||||
<el-tooltip effect="dark" content="在gitee找到我们" placement="bottom">
|
<el-tooltip effect="dark" content="在gitee找到我们" placement="bottom">
|
||||||
@@ -89,15 +109,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { Bell } from '@element-plus/icons-vue'
|
||||||
import AvatarInfo from "@/components/AvatarInfo.vue";
|
import AvatarInfo from "@/components/AvatarInfo.vue";
|
||||||
import { ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import useUserStore from "@/stores/user.js";
|
import useUserStore from "@/stores/user.js";
|
||||||
import useConfigStore from "@/stores/config";
|
import useConfigStore from "@/stores/config";
|
||||||
import useAuths from "@/hooks/useAuths";
|
import useAuths from "@/hooks/useAuths";
|
||||||
import { Session } from "@/utils/storage";
|
import { Session } from "@/utils/storage";
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
import useNoticeStore from "@/stores/notice";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { getList as getNoticeList, read as noticeRead } from "@/apis/bbsNoticeApi"
|
||||||
const { isLogin, clearStorage } = useAuths();
|
const { isLogin, clearStorage } = useAuths();
|
||||||
|
//消息通知存储
|
||||||
|
const noticeStore = useNoticeStore();
|
||||||
|
const { noticeList } = storeToRefs(noticeStore);
|
||||||
const configStore = useConfigStore();
|
const configStore = useConfigStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -105,6 +132,19 @@ const userStore = useUserStore();
|
|||||||
const { money } = storeToRefs(userStore)
|
const { money } = storeToRefs(userStore)
|
||||||
const activeIndex = ref("1");
|
const activeIndex = ref("1");
|
||||||
const searchText = ref("");
|
const searchText = ref("");
|
||||||
|
const noticeForNoReadCount=computed(()=>{
|
||||||
|
return noticeList.value.filter(x => x.isRead ==false).length;
|
||||||
|
})
|
||||||
|
//加载初始化离线消息
|
||||||
|
onMounted(async () => {
|
||||||
|
await fetchNoticeData();
|
||||||
|
})
|
||||||
|
const fetchNoticeData = async () => {
|
||||||
|
const { data } = await getNoticeList({maxResultCount:20});
|
||||||
|
noticeStore.setNotices(data.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleSelect = (key, keyPath) => {
|
const handleSelect = (key, keyPath) => {
|
||||||
console.log(key, keyPath);
|
console.log(key, keyPath);
|
||||||
};
|
};
|
||||||
@@ -130,7 +170,7 @@ const enterIndex = () => {
|
|||||||
const enterProfile = () => {
|
const enterProfile = () => {
|
||||||
router.push(`/profile/${userStore.userName}`);
|
router.push(`/profile/${userStore.userName}`);
|
||||||
};
|
};
|
||||||
const enterActivity=()=>{
|
const enterActivity = () => {
|
||||||
router.push(`/activity`);
|
router.push(`/activity`);
|
||||||
}
|
}
|
||||||
const toLogin = () => {
|
const toLogin = () => {
|
||||||
@@ -150,19 +190,33 @@ const handleGitClick = () => {
|
|||||||
const handleGithubClick = () => {
|
const handleGithubClick = () => {
|
||||||
window.open("https://github.com/ccnetcore/Yi.Abp.Admin");
|
window.open("https://github.com/ccnetcore/Yi.Abp.Admin");
|
||||||
};
|
};
|
||||||
|
///一键已读
|
||||||
|
const hanldeReadClick=async ()=>{
|
||||||
|
|
||||||
|
await noticeRead();
|
||||||
|
await fetchNoticeData();
|
||||||
|
|
||||||
|
ElMessage({
|
||||||
|
message: `全部已读`,
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.money
|
.money {
|
||||||
{
|
|
||||||
|
|
||||||
font-size: small;
|
font-size: small;
|
||||||
color: #FED055;
|
color: #FED055;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
span{
|
|
||||||
|
span {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
width: 1300px;
|
width: 1300px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -179,12 +233,14 @@ const handleGithubClick = () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gitee,
|
.gitee,
|
||||||
.github {
|
.github {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -196,31 +252,55 @@ const handleGithubClick = () => {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
.el-menu {
|
.el-menu {
|
||||||
height: 90%;
|
height: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-menu--horizontal) {
|
:deep(.el-menu--horizontal) {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-icon {
|
.img-icon {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notice {
|
||||||
|
margin: 0 5px;
|
||||||
|
&-oper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
&-msg {
|
||||||
|
white-space: wrap !important;
|
||||||
|
width: 400px;
|
||||||
|
padding: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
border-bottom: 1px solid #f0e9e9;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
33
Yi.Bbs.Vue3/src/stores/notice.js
Normal file
33
Yi.Bbs.Vue3/src/stores/notice.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
const chatStore = defineStore("notice", {
|
||||||
|
state: () => ({
|
||||||
|
noticeList: []
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
noticeForNoReadCount:(state)=>{
|
||||||
|
return state.noticeList.filter(x => x.isRead ==false).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
actions:
|
||||||
|
{
|
||||||
|
addNotice(msg) {
|
||||||
|
this.noticeList.unshift(msg);
|
||||||
|
},
|
||||||
|
addNotices(msgs) {
|
||||||
|
|
||||||
|
msgs.forEach(item => {
|
||||||
|
this.addNotice(item);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setNotices(msgs) {
|
||||||
|
this.noticeList=msgs;
|
||||||
|
},
|
||||||
|
removeNotice(id)
|
||||||
|
{
|
||||||
|
this.noticeList = this.noticeList.filter(obj => obj.id != id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default chatStore;
|
||||||
@@ -955,10 +955,10 @@ csstype@^2.6.8:
|
|||||||
resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz"
|
resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz"
|
||||||
integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
|
integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
|
||||||
|
|
||||||
dayjs@^1.11.10, dayjs@^1.11.3:
|
dayjs@^1.11.11, dayjs@^1.11.3:
|
||||||
version "1.11.10"
|
version "1.11.11"
|
||||||
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.10.tgz"
|
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.11.tgz"
|
||||||
integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
|
integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==
|
||||||
|
|
||||||
debug@^4.1.0, debug@^4.3.1, debug@^4.3.4, debug@4:
|
debug@^4.1.0, debug@^4.3.1, debug@^4.3.4, debug@4:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user