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 }; } }