HaniBlindBox/server/HoneyBox/src/HoneyBox.Admin.Business/Services/AdvertService.cs
2026-01-18 02:45:30 +08:00

359 lines
11 KiB
C#

using HoneyBox.Admin.Business.Models;
using HoneyBox.Admin.Business.Models.Advert;
using HoneyBox.Admin.Business.Services.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace HoneyBox.Admin.Business.Services;
/// <summary>
/// 广告管理服务实现
/// </summary>
public class AdvertService : IAdvertService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger<AdvertService> _logger;
public AdvertService(
HoneyBoxDbContext dbContext,
ILogger<AdvertService> logger)
{
_dbContext = dbContext;
_logger = logger;
}
#region 广
/// <inheritdoc />
public async Task<PagedResult<AdvertResponse>> GetAdvertsAsync(AdvertListRequest request)
{
var query = _dbContext.Adverts.AsNoTracking();
// 应用类型过滤
if (request.TypeId.HasValue)
{
query = query.Where(a => a.Type == request.TypeId.Value);
}
// 获取总数
var total = await query.CountAsync();
// 获取列表
var adverts = await query
.OrderBy(a => a.Sort)
.ThenByDescending(a => a.Id)
.Skip(request.Skip)
.Take(request.PageSize)
.ToListAsync();
// 获取类型名称映射
var typeIds = adverts.Select(a => (int)a.Type).Distinct().ToList();
var types = await _dbContext.AdvertTypes
.AsNoTracking()
.Where(t => typeIds.Contains(t.Id))
.ToDictionaryAsync(t => t.Id, t => t.Name);
// 映射结果
var list = adverts.Select(a => MapToResponse(a, types)).ToList();
return PagedResult<AdvertResponse>.Create(list, total, request.Page, request.PageSize);
}
/// <inheritdoc />
public async Task<AdvertResponse?> GetAdvertByIdAsync(int id)
{
var advert = await _dbContext.Adverts
.AsNoTracking()
.FirstOrDefaultAsync(a => a.Id == id);
if (advert == null)
return null;
// 获取类型名称
var typeName = await _dbContext.AdvertTypes
.AsNoTracking()
.Where(t => t.Id == advert.Type)
.Select(t => t.Name)
.FirstOrDefaultAsync() ?? "未知类型";
return MapToResponse(advert, new Dictionary<int, string> { { advert.Type, typeName } });
}
/// <inheritdoc />
public async Task<int> CreateAdvertAsync(AdvertCreateRequest request)
{
// 验证请求
await ValidateAdvertRequest(request);
var now = DateTime.Now;
var advert = new Advert
{
Type = (byte)request.TypeId,
ImgUrl = request.ImageUrl,
Sort = request.Sort,
Ttype = (byte)request.JumpType,
CouponId = request.CouponId ?? 0,
GoodsId = request.GoodsId ?? 0,
Url = request.UrlLink,
CreatedAt = now,
UpdatedAt = now
};
_dbContext.Adverts.Add(advert);
await _dbContext.SaveChangesAsync();
_logger.LogInformation("创建广告成功: Id={Id}, TypeId={TypeId}", advert.Id, request.TypeId);
return advert.Id;
}
/// <inheritdoc />
public async Task<bool> UpdateAdvertAsync(int id, AdvertUpdateRequest request)
{
var advert = await _dbContext.Adverts.FirstOrDefaultAsync(a => a.Id == id);
if (advert == null)
{
throw new BusinessException(BusinessErrorCodes.NotFound, "广告不存在");
}
// 验证请求
await ValidateAdvertRequest(request);
advert.Type = (byte)request.TypeId;
advert.ImgUrl = request.ImageUrl;
advert.Sort = request.Sort;
advert.Ttype = (byte)request.JumpType;
advert.CouponId = request.CouponId ?? 0;
advert.GoodsId = request.GoodsId ?? 0;
advert.Url = request.UrlLink;
advert.UpdatedAt = DateTime.Now;
var result = await _dbContext.SaveChangesAsync() > 0;
_logger.LogInformation("更新广告成功: Id={Id}", id);
return result;
}
/// <inheritdoc />
public async Task<bool> DeleteAdvertAsync(int id)
{
var advert = await _dbContext.Adverts.FirstOrDefaultAsync(a => a.Id == id);
if (advert == null)
{
throw new BusinessException(BusinessErrorCodes.NotFound, "广告不存在");
}
_dbContext.Adverts.Remove(advert);
var result = await _dbContext.SaveChangesAsync() > 0;
_logger.LogInformation("删除广告成功: Id={Id}", id);
return result;
}
#endregion
#region 广
/// <inheritdoc />
public async Task<List<AdvertTypeResponse>> GetAdvertTypesAsync()
{
// 获取所有类型
var types = await _dbContext.AdvertTypes
.AsNoTracking()
.OrderBy(t => t.Sort)
.ThenBy(t => t.Id)
.ToListAsync();
// 获取每个类型下的广告数量
var typeCounts = await _dbContext.Adverts
.AsNoTracking()
.GroupBy(a => a.Type)
.Select(g => new { TypeId = g.Key, Count = g.Count() })
.ToDictionaryAsync(x => (int)x.TypeId, x => x.Count);
return types.Select(t => new AdvertTypeResponse
{
Id = t.Id,
Name = t.Name,
Sort = t.Sort,
AdvertCount = typeCounts.GetValueOrDefault(t.Id, 0)
}).ToList();
}
/// <inheritdoc />
public async Task<int> CreateAdvertTypeAsync(AdvertTypeCreateRequest request)
{
// 验证名称
if (string.IsNullOrWhiteSpace(request.Name))
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "类型名称不能为空");
}
// 检查名称是否已存在
var exists = await _dbContext.AdvertTypes
.AnyAsync(t => t.Name == request.Name);
if (exists)
{
throw new BusinessException(BusinessErrorCodes.Conflict, "该类型名称已存在");
}
var now = DateTime.Now;
var advertType = new AdvertType
{
Name = request.Name,
Sort = request.Sort,
CreatedAt = now,
UpdatedAt = now
};
_dbContext.AdvertTypes.Add(advertType);
await _dbContext.SaveChangesAsync();
_logger.LogInformation("创建广告类型成功: Id={Id}, Name={Name}", advertType.Id, advertType.Name);
return advertType.Id;
}
/// <inheritdoc />
public async Task<bool> UpdateAdvertTypeAsync(int id, AdvertTypeUpdateRequest request)
{
var advertType = await _dbContext.AdvertTypes.FirstOrDefaultAsync(t => t.Id == id);
if (advertType == null)
{
throw new BusinessException(BusinessErrorCodes.NotFound, "广告类型不存在");
}
// 验证名称
if (string.IsNullOrWhiteSpace(request.Name))
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "类型名称不能为空");
}
// 检查名称是否被其他类型使用
var exists = await _dbContext.AdvertTypes
.AnyAsync(t => t.Name == request.Name && t.Id != id);
if (exists)
{
throw new BusinessException(BusinessErrorCodes.Conflict, "该类型名称已被其他类型使用");
}
advertType.Name = request.Name;
advertType.Sort = request.Sort;
advertType.UpdatedAt = DateTime.Now;
var result = await _dbContext.SaveChangesAsync() > 0;
_logger.LogInformation("更新广告类型成功: Id={Id}, Name={Name}", id, advertType.Name);
return result;
}
/// <inheritdoc />
public async Task<bool> DeleteAdvertTypeAsync(int id)
{
var advertType = await _dbContext.AdvertTypes.FirstOrDefaultAsync(t => t.Id == id);
if (advertType == null)
{
throw new BusinessException(BusinessErrorCodes.NotFound, "广告类型不存在");
}
// 检查该类型下是否有广告
var hasAdverts = await _dbContext.Adverts.AnyAsync(a => a.Type == id);
if (hasAdverts)
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "删除失败:该类型下仍有关联的广告,请先删除或移动这些广告");
}
_dbContext.AdvertTypes.Remove(advertType);
var result = await _dbContext.SaveChangesAsync() > 0;
_logger.LogInformation("删除广告类型成功: Id={Id}, Name={Name}", id, advertType.Name);
return result;
}
#endregion
#region Private Helper Methods
/// <summary>
/// 验证广告请求参数
/// </summary>
private async Task ValidateAdvertRequest(AdvertCreateRequest request)
{
// 验证图片URL
if (string.IsNullOrWhiteSpace(request.ImageUrl))
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "广告图片不能为空");
}
// 验证类型是否存在
var typeExists = await _dbContext.AdvertTypes.AnyAsync(t => t.Id == request.TypeId);
if (!typeExists)
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "选择的广告类型无效");
}
// 验证跳转类型
if (request.JumpType < 0 || request.JumpType > 5)
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "跳转类型无效");
}
// 根据跳转类型验证关联字段
switch (request.JumpType)
{
case AdvertJumpTypes.Coupon:
if (!request.CouponId.HasValue || request.CouponId <= 0)
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "请选择关联的优惠券");
}
break;
case AdvertJumpTypes.YiFanShang:
case AdvertJumpTypes.WuXianShang:
case AdvertJumpTypes.LianJiShang:
if (!request.GoodsId.HasValue || request.GoodsId <= 0)
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "请选择关联的盒子");
}
break;
case AdvertJumpTypes.CustomUrl:
if (string.IsNullOrWhiteSpace(request.UrlLink))
{
throw new BusinessException(BusinessErrorCodes.ValidationFailed, "请输入跳转链接");
}
break;
}
}
/// <summary>
/// 映射广告实体到响应模型
/// </summary>
private AdvertResponse MapToResponse(Advert advert, Dictionary<int, string> typeNames)
{
return new AdvertResponse
{
Id = advert.Id,
TypeId = advert.Type,
TypeName = typeNames.GetValueOrDefault(advert.Type, "未知类型"),
ImageUrl = advert.ImgUrl,
Sort = advert.Sort,
JumpType = advert.Ttype ?? 0,
JumpTypeName = AdvertJumpTypes.GetJumpTypeName(advert.Ttype ?? 0),
CouponId = advert.CouponId == 0 ? null : advert.CouponId,
GoodsId = advert.GoodsId == 0 ? null : advert.GoodsId,
UrlLink = advert.Url,
CreatedAt = advert.CreatedAt,
UpdatedAt = advert.UpdatedAt
};
}
#endregion
}