using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using MiAssessment.Admin.Business.Data; using MiAssessment.Admin.Business.Entities; using MiAssessment.Admin.Business.Models; using MiAssessment.Admin.Business.Models.Common; using MiAssessment.Admin.Business.Models.Content; using MiAssessment.Admin.Business.Services.Interfaces; namespace MiAssessment.Admin.Business.Services; /// /// 内容管理服务实现 /// public class ContentService : IContentService { private readonly AdminBusinessDbContext _dbContext; private readonly ILogger _logger; /// /// 跳转类型名称映射 /// private static readonly Dictionary LinkTypeNames = new() { { 0, "? }, { 1, "内部页面" }, { 2, "外部链接" }, { 3, "小程? } }; /// /// 状态名称映? /// private static readonly Dictionary StatusNames = new() { { 0, "禁用" }, { 1, "启用" } }; /// /// 宣传图位置名称映? /// private static readonly Dictionary PositionNames = new() { { 1, "首页底部" }, { 2, "团队? } }; /// /// 构造函? /// /// 数据库上下文 /// 日志记录?/param> public ContentService( AdminBusinessDbContext dbContext, ILogger logger) { _dbContext = dbContext; _logger = logger; } #region Banner 轮播图操? /// public async Task> GetBannerListAsync(BannerQueryRequest request) { // 构建查询,过滤软删除记录 var query = _dbContext.Banners .AsNoTracking() .Where(b => !b.IsDeleted); // 状态筛? if (request.Status.HasValue) { query = query.Where(b => b.Status == request.Status.Value); } // 获取总数 var total = await query.CountAsync(); // 分页查询,按 Sort 降序排列 var items = await query .OrderByDescending(b => b.Sort) .ThenByDescending(b => b.CreateTime) .Skip(request.Skip) .Take(request.PageSize) .Select(b => new BannerDto { Id = b.Id, Title = b.Title, ImageUrl = b.ImageUrl, LinkType = b.LinkType, LinkTypeName = GetLinkTypeName(b.LinkType), LinkUrl = b.LinkUrl, AppId = b.AppId, Sort = b.Sort, Status = b.Status, StatusName = GetStatusName(b.Status), CreateTime = b.CreateTime }) .ToListAsync(); return PagedResult.Create(items, total, request.Page, request.PageSize); } /// public async Task GetBannerByIdAsync(long id) { var banner = await _dbContext.Banners .AsNoTracking() .Where(b => b.Id == id && !b.IsDeleted) .Select(b => new BannerDto { Id = b.Id, Title = b.Title, ImageUrl = b.ImageUrl, LinkType = b.LinkType, LinkTypeName = GetLinkTypeName(b.LinkType), LinkUrl = b.LinkUrl, AppId = b.AppId, Sort = b.Sort, Status = b.Status, StatusName = GetStatusName(b.Status), CreateTime = b.CreateTime }) .FirstOrDefaultAsync(); if (banner == null) { throw new BusinessException(ErrorCodes.BannerNotFound, "轮播图不存在"); } return banner; } /// public async Task CreateBannerAsync(CreateBannerRequest request) { // 验证图片URL必填 if (string.IsNullOrWhiteSpace(request.ImageUrl)) { throw new BusinessException(ErrorCodes.BannerImageRequired, "图片URL不能为空"); } // 验证 LinkType 和对应字? ValidateLinkType(request.LinkType, request.LinkUrl, request.AppId); // 创建实体 var banner = new Banner { Title = request.Title, ImageUrl = request.ImageUrl, LinkType = request.LinkType, LinkUrl = request.LinkUrl, AppId = request.AppId, Sort = request.Sort, Status = request.Status, CreateTime = DateTime.Now, UpdateTime = DateTime.Now, IsDeleted = false }; _dbContext.Banners.Add(banner); await _dbContext.SaveChangesAsync(); _logger.LogInformation("创建轮播图成功,ID: {BannerId}, 标题: {Title}", banner.Id, banner.Title); return banner.Id; } /// public async Task UpdateBannerAsync(UpdateBannerRequest request) { // 查找轮播? var banner = await _dbContext.Banners .Where(b => b.Id == request.Id && !b.IsDeleted) .FirstOrDefaultAsync(); if (banner == null) { throw new BusinessException(ErrorCodes.BannerNotFound, "轮播图不存在"); } // 验证图片URL必填 if (string.IsNullOrWhiteSpace(request.ImageUrl)) { throw new BusinessException(ErrorCodes.BannerImageRequired, "图片URL不能为空"); } // 验证 LinkType 和对应字? ValidateLinkType(request.LinkType, request.LinkUrl, request.AppId); // 更新字段 banner.Title = request.Title; banner.ImageUrl = request.ImageUrl; banner.LinkType = request.LinkType; banner.LinkUrl = request.LinkUrl; banner.AppId = request.AppId; banner.Sort = request.Sort; banner.Status = request.Status; banner.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("更新轮播图成功,ID: {BannerId}", banner.Id); return true; } /// public async Task DeleteBannerAsync(long id) { // 查找轮播? var banner = await _dbContext.Banners .Where(b => b.Id == id && !b.IsDeleted) .FirstOrDefaultAsync(); if (banner == null) { throw new BusinessException(ErrorCodes.BannerNotFound, "轮播图不存在"); } // 软删? banner.IsDeleted = true; banner.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("删除轮播图成功,ID: {BannerId}", id); return true; } /// public async Task UpdateBannerStatusAsync(long id, int status) { // 查找轮播? var banner = await _dbContext.Banners .Where(b => b.Id == id && !b.IsDeleted) .FirstOrDefaultAsync(); if (banner == null) { throw new BusinessException(ErrorCodes.BannerNotFound, "轮播图不存在"); } // 更新状? banner.Status = status; banner.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("更新轮播图状态成功,ID: {BannerId}, 状? {Status}", id, status); return true; } /// public async Task UpdateBannerSortAsync(List items) { if (items == null || items.Count == 0) { return true; } // 获取所有需要更新的轮播图ID var ids = items.Select(i => i.Id).ToList(); // 批量查询轮播? var banners = await _dbContext.Banners .Where(b => ids.Contains(b.Id) && !b.IsDeleted) .ToListAsync(); // 更新排序 foreach (var item in items) { var banner = banners.FirstOrDefault(b => b.Id == item.Id); if (banner != null) { banner.Sort = item.Sort; banner.UpdateTime = DateTime.Now; } } await _dbContext.SaveChangesAsync(); _logger.LogInformation("批量更新轮播图排序成功,更新数量: {Count}", items.Count); return true; } #endregion #region Promotion 宣传图操? /// public async Task> GetPromotionListAsync(PromotionQueryRequest request) { // 构建查询,过滤软删除记录 var query = _dbContext.Promotions .AsNoTracking() .Where(p => !p.IsDeleted); // 位置筛? if (request.Position.HasValue) { query = query.Where(p => p.Position == request.Position.Value); } // 状态筛? if (request.Status.HasValue) { query = query.Where(p => p.Status == request.Status.Value); } // 获取总数 var total = await query.CountAsync(); // 分页查询,按 Sort 降序排列 var items = await query .OrderByDescending(p => p.Sort) .ThenByDescending(p => p.CreateTime) .Skip(request.Skip) .Take(request.PageSize) .Select(p => new PromotionDto { Id = p.Id, Title = p.Title, ImageUrl = p.ImageUrl, Position = p.Position, PositionName = GetPositionName(p.Position), Sort = p.Sort, Status = p.Status, StatusName = GetStatusName(p.Status), CreateTime = p.CreateTime }) .ToListAsync(); return PagedResult.Create(items, total, request.Page, request.PageSize); } /// public async Task GetPromotionByIdAsync(long id) { var promotion = await _dbContext.Promotions .AsNoTracking() .Where(p => p.Id == id && !p.IsDeleted) .Select(p => new PromotionDto { Id = p.Id, Title = p.Title, ImageUrl = p.ImageUrl, Position = p.Position, PositionName = GetPositionName(p.Position), Sort = p.Sort, Status = p.Status, StatusName = GetStatusName(p.Status), CreateTime = p.CreateTime }) .FirstOrDefaultAsync(); if (promotion == null) { throw new BusinessException(ErrorCodes.PromotionNotFound, "宣传图不存在"); } return promotion; } /// public async Task CreatePromotionAsync(CreatePromotionRequest request) { // 验证图片URL必填 if (string.IsNullOrWhiteSpace(request.ImageUrl)) { throw new BusinessException(ErrorCodes.PromotionImageRequired, "图片URL不能为空"); } // 验证 Position ? ValidatePosition(request.Position); // 创建实体 var promotion = new Promotion { Title = request.Title, ImageUrl = request.ImageUrl, Position = request.Position, Sort = request.Sort, Status = request.Status, CreateTime = DateTime.Now, UpdateTime = DateTime.Now, IsDeleted = false }; _dbContext.Promotions.Add(promotion); await _dbContext.SaveChangesAsync(); _logger.LogInformation("创建宣传图成功,ID: {PromotionId}, 标题: {Title}, 位置: {Position}", promotion.Id, promotion.Title, promotion.Position); return promotion.Id; } /// public async Task UpdatePromotionAsync(UpdatePromotionRequest request) { // 查找宣传? var promotion = await _dbContext.Promotions .Where(p => p.Id == request.Id && !p.IsDeleted) .FirstOrDefaultAsync(); if (promotion == null) { throw new BusinessException(ErrorCodes.PromotionNotFound, "宣传图不存在"); } // 验证图片URL必填 if (string.IsNullOrWhiteSpace(request.ImageUrl)) { throw new BusinessException(ErrorCodes.PromotionImageRequired, "图片URL不能为空"); } // 验证 Position ? ValidatePosition(request.Position); // 更新字段 promotion.Title = request.Title; promotion.ImageUrl = request.ImageUrl; promotion.Position = request.Position; promotion.Sort = request.Sort; promotion.Status = request.Status; promotion.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("更新宣传图成功,ID: {PromotionId}", promotion.Id); return true; } /// public async Task DeletePromotionAsync(long id) { // 查找宣传? var promotion = await _dbContext.Promotions .Where(p => p.Id == id && !p.IsDeleted) .FirstOrDefaultAsync(); if (promotion == null) { throw new BusinessException(ErrorCodes.PromotionNotFound, "宣传图不存在"); } // 软删? promotion.IsDeleted = true; promotion.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("删除宣传图成功,ID: {PromotionId}", id); return true; } /// public async Task UpdatePromotionStatusAsync(long id, int status) { // 查找宣传? var promotion = await _dbContext.Promotions .Where(p => p.Id == id && !p.IsDeleted) .FirstOrDefaultAsync(); if (promotion == null) { throw new BusinessException(ErrorCodes.PromotionNotFound, "宣传图不存在"); } // 更新状? promotion.Status = status; promotion.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("更新宣传图状态成功,ID: {PromotionId}, 状? {Status}", id, status); return true; } #endregion #region 私有方法 /// /// 验证 LinkType 和对应字? /// /// 跳转类型 /// 跳转地址 /// 小程序AppId private void ValidateLinkType(int linkType, string? linkUrl, string? appId) { switch (linkType) { case 0: // 无跳转,不需要验? break; case 1: case 2: // 内部页面或外部链接,LinkUrl 必填 if (string.IsNullOrWhiteSpace(linkUrl)) { throw new BusinessException(ErrorCodes.BannerLinkUrlRequired, "跳转地址不能为空"); } break; case 3: // 小程序,LinkUrl ?AppId 都必? if (string.IsNullOrWhiteSpace(linkUrl)) { throw new BusinessException(ErrorCodes.BannerLinkUrlRequired, "跳转地址不能为空"); } if (string.IsNullOrWhiteSpace(appId)) { throw new BusinessException(ErrorCodes.BannerLinkUrlRequired, "小程序AppId不能为空"); } break; } } /// /// 获取跳转类型名称 /// /// 跳转类型 /// 类型名称 private static string GetLinkTypeName(int linkType) { return LinkTypeNames.TryGetValue(linkType, out var name) ? name : "未知"; } /// /// 获取状态名? /// /// 状态?/param> /// 状态名?/returns> private static string GetStatusName(int status) { return StatusNames.TryGetValue(status, out var name) ? name : "未知"; } /// /// 获取位置名称 /// /// 位置?/param> /// 位置名称 private static string GetPositionName(int position) { return PositionNames.TryGetValue(position, out var name) ? name : "未知"; } /// /// 导航状态名称映? /// private static readonly Dictionary NavigationStatusNames = new() { { 0, "即将上线" }, { 1, "已上? } }; /// /// 验证 Position ? /// /// 位置?/param> private void ValidatePosition(int position) { if (position != 1 && position != 2) { throw new BusinessException(ErrorCodes.ParamError, "位置值必须为1(首页底部)?(团队页?); } } #endregion #region HomeNavigation 首页导航操作 /// public async Task> GetNavigationListAsync(HomeNavigationQueryRequest request) { var query = _dbContext.HomeNavigations .AsNoTracking() .Where(n => !n.IsDeleted); if (!string.IsNullOrWhiteSpace(request.Name)) { query = query.Where(n => n.Name.Contains(request.Name)); } if (request.Status.HasValue) { query = query.Where(n => n.Status == request.Status.Value); } var total = await query.CountAsync(); var items = await query .OrderByDescending(n => n.Sort) .ThenByDescending(n => n.CreateTime) .Skip(request.Skip) .Take(request.PageSize) .Select(n => new HomeNavigationDto { Id = n.Id, Name = n.Name, ImageUrl = n.ImageUrl, LinkUrl = n.LinkUrl, Sort = n.Sort, Status = n.Status, StatusName = NavigationStatusNames.ContainsKey(n.Status) ? NavigationStatusNames[n.Status] : "未知", CreateTime = n.CreateTime }) .ToListAsync(); return PagedResult.Create(items, total, request.Page, request.PageSize); } /// public async Task GetNavigationByIdAsync(long id) { var nav = await _dbContext.HomeNavigations .AsNoTracking() .Where(n => n.Id == id && !n.IsDeleted) .Select(n => new HomeNavigationDto { Id = n.Id, Name = n.Name, ImageUrl = n.ImageUrl, LinkUrl = n.LinkUrl, Sort = n.Sort, Status = n.Status, StatusName = NavigationStatusNames.ContainsKey(n.Status) ? NavigationStatusNames[n.Status] : "未知", CreateTime = n.CreateTime }) .FirstOrDefaultAsync(); if (nav == null) { throw new BusinessException(ErrorCodes.NavigationNotFound, "首页导航不存?); } return nav; } /// public async Task CreateNavigationAsync(CreateHomeNavigationRequest request) { if (string.IsNullOrWhiteSpace(request.Name)) { throw new BusinessException(ErrorCodes.ParamError, "导航名称不能为空"); } var entity = new HomeNavigation { Name = request.Name, ImageUrl = request.ImageUrl, LinkUrl = request.LinkUrl, Sort = request.Sort, Status = request.Status, CreateTime = DateTime.Now, UpdateTime = DateTime.Now, IsDeleted = false }; _dbContext.HomeNavigations.Add(entity); await _dbContext.SaveChangesAsync(); _logger.LogInformation("创建首页导航成功,ID: {Id}, 名称: {Name}", entity.Id, entity.Name); return entity.Id; } /// public async Task UpdateNavigationAsync(UpdateHomeNavigationRequest request) { var entity = await _dbContext.HomeNavigations .Where(n => n.Id == request.Id && !n.IsDeleted) .FirstOrDefaultAsync(); if (entity == null) { throw new BusinessException(ErrorCodes.NavigationNotFound, "首页导航不存?); } if (string.IsNullOrWhiteSpace(request.Name)) { throw new BusinessException(ErrorCodes.ParamError, "导航名称不能为空"); } entity.Name = request.Name; entity.ImageUrl = request.ImageUrl; entity.LinkUrl = request.LinkUrl; entity.Sort = request.Sort; entity.Status = request.Status; entity.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("更新首页导航成功,ID: {Id}", entity.Id); return true; } /// public async Task DeleteNavigationAsync(long id) { var entity = await _dbContext.HomeNavigations.FindAsync(id); if (entity == null || entity.IsDeleted) return false; entity.IsDeleted = true; entity.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("删除首页导航成功,ID: {Id}", id); return true; } /// public async Task UpdateNavigationStatusAsync(long id, int status) { var entity = await _dbContext.HomeNavigations .Where(n => n.Id == id && !n.IsDeleted) .FirstOrDefaultAsync(); if (entity == null) { throw new BusinessException(ErrorCodes.NavigationNotFound, "首页导航不存?); } entity.Status = status; entity.UpdateTime = DateTime.Now; await _dbContext.SaveChangesAsync(); _logger.LogInformation("更新首页导航状态成功,ID: {Id}, 状? {Status}", id, status); return true; } #endregion }