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;
///
/// 公告服务
///
public class AnnouncementService : ApplicationService, IAnnouncementService
{
private readonly ISqlSugarRepository _announcementRepository;
private readonly IConfiguration _configuration;
private readonly IDistributedCache _announcementCache;
private const string AnnouncementCacheKey = "AiHub:Announcement";
public AnnouncementService(
ISqlSugarRepository announcementRepository,
IConfiguration configuration,
IDistributedCache announcementCache)
{
_announcementRepository = announcementRepository;
_configuration = configuration;
_announcementCache = announcementCache;
}
///
/// 获取公告信息(前端首页使用,允许匿名访问)
///
[AllowAnonymous]
public async Task> GetAsync()
{
// 使用 GetOrAddAsync 从缓存获取或添加数据,缓存1小时
var cacheData = await _announcementCache.GetOrAddAsync(
AnnouncementCacheKey,
async () => await LoadAnnouncementDataAsync(),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
}
);
return cacheData?.Logs ?? new List();
}
///
/// 获取公告列表(后台管理使用)
///
[Authorize(Roles = "admin")]
[HttpGet("announcement/list")]
public async Task> 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(
totalCount,
items.Adapt>()
);
}
///
/// 根据ID获取公告
///
[Authorize(Roles = "admin")]
[HttpGet("{id}")]
public async Task GetByIdAsync(Guid id)
{
var entity = await _announcementRepository.GetByIdAsync(id);
if (entity == null)
{
throw new Exception("公告不存在");
}
return entity.Adapt();
}
///
/// 创建公告
///
[Authorize(Roles = "admin")]
[HttpPost]
public async Task CreateAsync(AnnouncementCreateInput input)
{
var entity = input.Adapt();
await _announcementRepository.InsertAsync(entity);
// 清除缓存
await _announcementCache.RemoveAsync(AnnouncementCacheKey);
return entity.Adapt();
}
///
/// 更新公告
///
[Authorize(Roles = "admin")]
[HttpPut]
public async Task 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();
}
///
/// 删除公告
///
[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);
}
///
/// 从数据库加载公告数据
///
private async Task 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>();
return new AnnouncementCacheDto
{
Logs = logDtos
};
}
}