190 lines
5.9 KiB
C#
190 lines
5.9 KiB
C#
using Mapster;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.Caching.Distributed;
|
||
using Microsoft.Extensions.Configuration;
|
||
using SqlSugar;
|
||
using Volo.Abp.Application.Dtos;
|
||
using Volo.Abp.Application.Services;
|
||
using Volo.Abp.Caching;
|
||
using Yi.Framework.AiHub.Application.Contracts.Dtos.Announcement;
|
||
using Yi.Framework.AiHub.Application.Contracts.IServices;
|
||
using Yi.Framework.AiHub.Domain.Entities;
|
||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||
|
||
namespace Yi.Framework.AiHub.Application.Services;
|
||
|
||
/// <summary>
|
||
/// 公告服务
|
||
/// </summary>
|
||
public class AnnouncementService : ApplicationService, IAnnouncementService
|
||
{
|
||
private readonly ISqlSugarRepository<AnnouncementAggregateRoot> _announcementRepository;
|
||
private readonly IConfiguration _configuration;
|
||
private readonly IDistributedCache<AnnouncementCacheDto> _announcementCache;
|
||
private const string AnnouncementCacheKey = "AiHub:Announcement";
|
||
|
||
public AnnouncementService(
|
||
ISqlSugarRepository<AnnouncementAggregateRoot> announcementRepository,
|
||
IConfiguration configuration,
|
||
IDistributedCache<AnnouncementCacheDto> announcementCache)
|
||
{
|
||
_announcementRepository = announcementRepository;
|
||
_configuration = configuration;
|
||
_announcementCache = announcementCache;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取公告信息(前端首页使用,允许匿名访问)
|
||
/// </summary>
|
||
[AllowAnonymous]
|
||
public async Task<List<AnnouncementLogDto>> GetAsync()
|
||
{
|
||
// 使用 GetOrAddAsync 从缓存获取或添加数据,缓存1小时
|
||
var cacheData = await _announcementCache.GetOrAddAsync(
|
||
AnnouncementCacheKey,
|
||
async () => await LoadAnnouncementDataAsync(),
|
||
() => new DistributedCacheEntryOptions
|
||
{
|
||
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
|
||
}
|
||
);
|
||
|
||
return cacheData?.Logs ?? new List<AnnouncementLogDto>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取公告列表(后台管理使用)
|
||
/// </summary>
|
||
[Authorize(Roles = "admin")]
|
||
[HttpGet("announcement/list")]
|
||
public async Task<PagedResultDto<AnnouncementDto>> GetListAsync(AnnouncementGetListInput input)
|
||
{
|
||
var query = _announcementRepository._DbQueryable
|
||
.WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey),
|
||
x => x.Title.Contains(input.SearchKey!) || (x.Remark != null && x.Remark.Contains(input.SearchKey!)))
|
||
.WhereIF(input.Type.HasValue, x => x.Type == input.Type!.Value)
|
||
.OrderByDescending(x => x.StartTime);
|
||
|
||
var totalCount = await query.CountAsync();
|
||
var items = await query
|
||
.Skip(input.SkipCount)
|
||
.Take(input.MaxResultCount)
|
||
.ToListAsync();
|
||
|
||
return new PagedResultDto<AnnouncementDto>(
|
||
totalCount,
|
||
items.Adapt<List<AnnouncementDto>>()
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据ID获取公告
|
||
/// </summary>
|
||
[Authorize(Roles = "admin")]
|
||
[HttpGet("{id}")]
|
||
public async Task<AnnouncementDto> GetByIdAsync(Guid id)
|
||
{
|
||
var entity = await _announcementRepository.GetByIdAsync(id);
|
||
if (entity == null)
|
||
{
|
||
throw new Exception("公告不存在");
|
||
}
|
||
return entity.Adapt<AnnouncementDto>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建公告
|
||
/// </summary>
|
||
[Authorize(Roles = "admin")]
|
||
[HttpPost]
|
||
public async Task<AnnouncementDto> CreateAsync(AnnouncementCreateInput input)
|
||
{
|
||
var entity = input.Adapt<AnnouncementAggregateRoot>();
|
||
await _announcementRepository.InsertAsync(entity);
|
||
|
||
// 清除缓存
|
||
await _announcementCache.RemoveAsync(AnnouncementCacheKey);
|
||
|
||
return entity.Adapt<AnnouncementDto>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新公告
|
||
/// </summary>
|
||
[Authorize(Roles = "admin")]
|
||
[HttpPut]
|
||
public async Task<AnnouncementDto> UpdateAsync(AnnouncementUpdateInput input)
|
||
{
|
||
var entity = await _announcementRepository.GetByIdAsync(input.Id);
|
||
if (entity == null)
|
||
{
|
||
throw new Exception("公告不存在");
|
||
}
|
||
|
||
// 更新字段
|
||
entity.Title = input.Title;
|
||
entity.Content = input.Content;
|
||
entity.Remark = input.Remark;
|
||
entity.ImageUrl = input.ImageUrl;
|
||
entity.StartTime = input.StartTime;
|
||
entity.EndTime = input.EndTime;
|
||
entity.Type = input.Type;
|
||
entity.Url = input.Url;
|
||
|
||
await _announcementRepository.UpdateAsync(entity);
|
||
|
||
// 清除缓存
|
||
await _announcementCache.RemoveAsync(AnnouncementCacheKey);
|
||
|
||
return entity.Adapt<AnnouncementDto>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除公告
|
||
/// </summary>
|
||
[Authorize(Roles = "admin")]
|
||
[HttpDelete("announcement/{id}")]
|
||
public async Task DeleteAsync(Guid id)
|
||
{
|
||
var entity = await _announcementRepository.GetByIdAsync(id);
|
||
if (entity == null)
|
||
{
|
||
throw new Exception("公告不存在");
|
||
}
|
||
|
||
await _announcementRepository.DeleteAsync(entity);
|
||
|
||
// 清除缓存
|
||
await _announcementCache.RemoveAsync(AnnouncementCacheKey);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从数据库加载公告数据
|
||
/// </summary>
|
||
private async Task<AnnouncementCacheDto> LoadAnnouncementDataAsync()
|
||
{
|
||
// 一次性查出全部公告(不排序)
|
||
var logs = await _announcementRepository._DbQueryable
|
||
.ToListAsync();
|
||
|
||
var now = DateTime.Now;
|
||
|
||
// 内存中处理排序
|
||
var orderedLogs = logs
|
||
.OrderByDescending(x =>
|
||
x.StartTime <= now &&
|
||
(x.EndTime == null || x.EndTime >= now)
|
||
)
|
||
.ThenByDescending(x => x.StartTime)
|
||
.ToList();
|
||
|
||
// 转换为 DTO
|
||
var logDtos = orderedLogs.Adapt<List<AnnouncementLogDto>>();
|
||
return new AnnouncementCacheDto
|
||
{
|
||
Logs = logDtos
|
||
};
|
||
}
|
||
}
|