feat: 社区新增有偿悬赏功能

This commit is contained in:
橙子
2025-04-12 23:18:06 +08:00
parent 91b216c06e
commit 87a14ebac1
21 changed files with 511 additions and 179 deletions

View File

@@ -5,8 +5,10 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
/// <summary>
/// Discuss输入创建对象
/// </summary>
public class DiscussCreateInputVo
public class DiscussCreateInput
{
public DiscussTypeEnum DiscussType { get; set; }
public string Title { get; set; }
public string? Types { get; set; }
public string? Introduction { get; set; }
@@ -41,5 +43,29 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
/// 角色
/// </summary>
public List<string>? PermissionRoleCodes { get; set; } = new List<string>();
/// <summary>
/// 悬赏类型主题
/// </summary>
public DiscussRewardCreateInput? RewardData { get; set; }
}
public class DiscussRewardCreateInput
{
/// <summary>
/// 悬赏最小价值
/// </summary>
public decimal MinValue { get; set; }
/// <summary>
/// 悬赏最大价值
/// </summary>
public decimal? MaxValue { get; set; }
/// <summary>
/// 作者联系方式
/// </summary>
public string Contact { get; set; }
}
}

View File

@@ -32,6 +32,8 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
//是否置顶默认false
public bool IsTop { get; set; }
public DiscussTypeEnum DiscussType { get; set; }
public DiscussPermissionTypeEnum PermissionType { get; set; }
//是否禁止默认false
public bool IsBan { get; set; }

View File

@@ -24,7 +24,10 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
public Guid PlateId { get; set; }
//是否置顶默认false
public bool IsTop { get; set; }
/// <summary>
/// 主题类型
/// </summary>
public DiscussTypeEnum DiscussType { get; set; }
/// <summary>
/// 封面
/// </summary>
@@ -50,6 +53,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
public bool HasPermission { get;internal set; }
public DiscussRewardGetOutputDto? RewardData { get; set; }
/// <summary>
/// 设置权限
/// </summary>

View File

@@ -0,0 +1,23 @@
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss;
public class DiscussRewardGetOutputDto
{
/// <summary>
/// 是否已解决
/// </summary>
public bool IsResolved{ get; set; }
/// <summary>
/// 悬赏最小价值
/// </summary>
public decimal MinValue { get; set; }
/// <summary>
/// 悬赏最大价值
/// </summary>
public decimal? MaxValue { get; set; }
/// <summary>
/// 作者联系方式
/// </summary>
public string Contact { get; set; }
}

View File

@@ -2,7 +2,7 @@ using Yi.Framework.Bbs.Domain.Shared.Enums;
namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
{
public class DiscussUpdateInputVo
public class DiscussUpdateInput
{
public string Title { get; set; }
public string? Types { get; set; }

View File

@@ -6,7 +6,7 @@ namespace Yi.Framework.Bbs.Application.Contracts.IServices
/// <summary>
/// Discuss服务抽象
/// </summary>
public interface IDiscussService : IYiCrudAppService<DiscussGetOutputDto, DiscussGetListOutputDto, Guid, DiscussGetListInputVo, DiscussCreateInputVo, DiscussUpdateInputVo>
public interface IDiscussService : IYiCrudAppService<DiscussGetOutputDto, DiscussGetListOutputDto, Guid, DiscussGetListInputVo, DiscussCreateInput, DiscussUpdateInput>
{
}
}

View File

@@ -33,7 +33,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
/// Discuss应用服务实现,用于参数校验、领域服务业务组合、日志记录、事务处理、账户信息
/// </summary>
public class DiscussService : YiCrudAppService<DiscussAggregateRoot, DiscussGetOutputDto, DiscussGetListOutputDto,
Guid, DiscussGetListInputVo, DiscussCreateInputVo, DiscussUpdateInputVo>,
Guid, DiscussGetListInputVo, DiscussCreateInput, DiscussUpdateInput>,
IDiscussService
{
private ISqlSugarRepository<DiscussTopEntity> _discussTopRepository;
@@ -102,6 +102,17 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
{
throw new UserFriendlyException("该主题不存在", "404");
}
switch (output.DiscussType)
{
case DiscussTypeEnum.Article: break;
//查询的是悬赏主题
case DiscussTypeEnum.Reward:
var reward= await _forumManager._discussRewardRepository.GetAsync(x=>x.DiscussId==output.Id);
output.RewardData = reward.Adapt<DiscussRewardGetOutputDto>();
break;
}
//组装点赞
var agreeCreatorList =
@@ -277,7 +288,7 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
/// <returns></returns>
[Permission("bbs:discuss:add")]
[Authorize]
public override async Task<DiscussGetOutputDto> CreateAsync(DiscussCreateInputVo input)
public override async Task<DiscussGetOutputDto> CreateAsync(DiscussCreateInput input)
{
var plate = await _plateEntityRepository.FindAsync(x => x.Id == input.PlateId);
if (plate is null)
@@ -300,12 +311,31 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
}
}
var entity = await _forumManager.CreateDiscussAsync(await MapToEntityAsync(input));
var entity = await _forumManager.CreateDiscussAsync(await MapToEntityAsync(input),input.RewardData.Adapt<DiscussRewardAggregateRoot>());
return await MapToGetOutputDtoAsync(entity);
}
/// <summary>
/// 设置悬赏主题已解决
/// </summary>
/// <param name="discussId"></param>
/// <exception cref="UserFriendlyException"></exception>
[HttpPut("discuss/reward/resolve/{discussId}")]
[Authorize]
public async Task SetRewardResolvedAsync([FromRoute]Guid discussId)
{
var reward= await _forumManager._discussRewardRepository.GetFirstAsync(x=>x.DiscussId==discussId);
if (reward is null)
{
throw new UserFriendlyException("未找到该悬赏主题","404");
}
public override Task<DiscussGetOutputDto> UpdateAsync(Guid id, DiscussUpdateInputVo input)
//设置已解决
reward.SetResolved();
await _forumManager._discussRewardRepository.UpdateAsync(reward);
}
public override Task<DiscussGetOutputDto> UpdateAsync(Guid id, DiscussUpdateInput input)
{
return base.UpdateAsync(id, input);
}

View File

@@ -0,0 +1,17 @@
namespace Yi.Framework.Bbs.Domain.Shared.Enums;
/// <summary>
/// 主题类型
/// </summary>
public enum DiscussTypeEnum
{
/// <summary>
/// 文章
/// </summary>
Article = 0,
/// <summary>
/// 悬赏
/// </summary>
Reward=1
}

View File

@@ -39,6 +39,11 @@ namespace Yi.Framework.Bbs.Domain.Entities.Forum
public string? Introduction { get; set; }
public int AgreeNum { get; set; }
public int SeeNum { get; set; }
/// <summary>
/// 主题类型
/// </summary>
public DiscussTypeEnum DiscussType { get; set; }
/// <summary>
/// 封面
/// </summary>

View File

@@ -0,0 +1,38 @@
using SqlSugar;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
namespace Yi.Framework.Bbs.Domain.Entities.Forum;
[SugarTable("DiscussReward")]
[SugarIndex($"index_{nameof(DiscussId)}", nameof(DiscussId), OrderByType.Asc)]
public class DiscussRewardAggregateRoot : FullAuditedAggregateRoot<Guid>
{
public Guid DiscussId { get; set; }
/// <summary>
/// 是否已解决
/// </summary>
public bool IsResolved{ get; set; }
/// <summary>
/// 悬赏最小价值
/// </summary>
public decimal? MinValue { get; set; }
/// <summary>
/// 悬赏最大价值
/// </summary>
public decimal? MaxValue { get; set; }
/// <summary>
/// 作者联系方式
/// </summary>
public string Contact { get; set; }
public void SetResolved()
{
IsResolved = true;
}
}

View File

@@ -21,21 +21,30 @@ namespace Yi.Framework.Bbs.Domain.Managers
public readonly ISqlSugarRepository<PlateAggregateRoot, Guid> _plateEntityRepository;
public readonly ISqlSugarRepository<CommentAggregateRoot, Guid> _commentRepository;
public readonly ISqlSugarRepository<ArticleAggregateRoot, Guid> _articleRepository;
public ForumManager(ISqlSugarRepository<DiscussAggregateRoot, Guid> discussRepository, ISqlSugarRepository<PlateAggregateRoot, Guid> plateEntityRepository, ISqlSugarRepository<CommentAggregateRoot, Guid> commentRepository, ISqlSugarRepository<ArticleAggregateRoot, Guid> articleRepository)
public readonly ISqlSugarRepository<DiscussRewardAggregateRoot,Guid> _discussRewardRepository;
public ForumManager(ISqlSugarRepository<DiscussAggregateRoot, Guid> discussRepository, ISqlSugarRepository<PlateAggregateRoot, Guid> plateEntityRepository, ISqlSugarRepository<CommentAggregateRoot, Guid> commentRepository, ISqlSugarRepository<ArticleAggregateRoot, Guid> articleRepository, ISqlSugarRepository<DiscussRewardAggregateRoot, Guid> discussRewardRepository)
{
_discussRepository = discussRepository;
_plateEntityRepository = plateEntityRepository;
_commentRepository = commentRepository;
_articleRepository = articleRepository;
_discussRewardRepository = discussRewardRepository;
}
//主题是不能直接创建的,需要由领域服务统一创建
public async Task<DiscussAggregateRoot> CreateDiscussAsync(DiscussAggregateRoot entity)
public async Task<DiscussAggregateRoot> CreateDiscussAsync(DiscussAggregateRoot entity,DiscussRewardAggregateRoot rewardEntity=null)
{
entity.CreationTime = DateTime.Now;
entity.AgreeNum = 0;
entity.SeeNum = 0;
return await _discussRepository.InsertReturnEntityAsync(entity);
var discuss = await _discussRepository.InsertReturnEntityAsync(entity);
if (discuss.DiscussType==DiscussTypeEnum.Reward)
{
rewardEntity.DiscussId=discuss.Id;
Check.NotNull(rewardEntity,"悬赏类型,悬赏信息不能为空");
await _discussRewardRepository.InsertAsync(rewardEntity);
}
return discuss;
}
public async Task<CommentAggregateRoot> CreateCommentAsync(Guid discussId, Guid parentId, Guid rootId, string content)

View File

@@ -37,10 +37,10 @@ namespace Yi.Framework.Bbs.Domain.Managers
/// <returns></returns>
public async Task<Dictionary<int, LevelCacheItem>> GetCacheMapAsync()
{
var items = _levelCache.GetOrAdd(LevelConst.LevelCacheKey, () =>
var items =await _levelCache.GetOrAddAsync(LevelConst.LevelCacheKey,async () =>
{
var cacheItem = (_repository.GetListAsync().Result)
.OrderByDescending(x => x.CurrentLevel).ToList()
var cacheItem = ((await _repository.GetListAsync())
.OrderByDescending(x => x.CurrentLevel))
.Adapt<List<LevelCacheItem>>();
return cacheItem;
});