Files
StopShopping/StopShopping.Services/Implementions/CategoryService.cs
2026-03-25 14:55:34 +08:00

202 lines
6.2 KiB
C#

using System.Data.Common;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using StopShopping.EF;
using StopShopping.Services.Models.Req;
using StopShopping.Services.Models.Resp;
namespace StopShopping.Services.Implementions;
public class CategoryService : ICategoryService
{
public CategoryService(
IFileService fileService,
StopShoppingContext dbContext,
ILogger<CategoryService> logger
)
{
_fileService = fileService;
_dbContext = dbContext;
_logger = logger;
}
private readonly IFileService _fileService;
private readonly StopShoppingContext _dbContext;
private readonly ILogger<CategoryService> _logger;
public async Task<ApiResponse> DeleteCategoryAsync(CategoryIdParams model)
{
var category = await _dbContext.Categories
.AsNoTracking()
.FirstOrDefaultAsync(c => c.Id == model.CategoryId && !c.Deleted);
if (null == category)
return ApiResponse.Failed("此分类已不存在,请刷新重试");
var anyProduct = await _dbContext.Products
.AsNoTracking()
.AnyAsync(p =>
_dbContext.Categories
.AsNoTracking()
.Where(c => c.Path.StartsWith(category.Path) && !c.Deleted)
.Select(c => c.Id)
.Contains(p.CategoryId));
if (anyProduct)
return ApiResponse.Failed("分类下已有商品,不允许删除");
await _dbContext.Categories
.Where(c => c.Path.StartsWith(category.Path) && !c.Deleted)
.ExecuteDeleteAsync();
return ApiResponse.Succed();
}
public async Task<ApiResponse<Category>> EditCategoryAsync(EditCategoryParams model)
{
EF.Models.Category category;
using var trans = await _dbContext.Database.BeginTransactionAsync();
try
{
short level = 1, order = 1;
string path = string.Empty;
var parent = await _dbContext.Categories
.FirstOrDefaultAsync(c => c.Id == model.ParentId);
if (null != parent)
level = (short)(parent.Level + 1);
if (model.Id > 0)
{
category = await _dbContext.Categories
.FirstAsync(c => c.Id == model.Id && !c.Deleted);
if (null == category)
return new ApiResponse<Category>().Failed("此分类已不存在");
path = category.Path;
order = category.Order;
}
else
{
category = new EF.Models.Category();
await _dbContext.Categories.AddAsync(category);
order = await _dbContext.Categories
.Where(c => c.ParentId == model.ParentId)
.Select(c => c.Order)
.DefaultIfEmpty()
.MaxAsync();
}
category.Level = level;
if (!string.IsNullOrWhiteSpace(model.Logo))
category.Logo = model.Logo;
category.Name = model.Name;
category.Order = order;
category.ParentId = model.ParentId;
category.Path = path;
await _dbContext.SaveChangesAsync();
if (!(model.Id > 0))
{
category.Path = BuildPath(parent?.Path ?? "", category.Id);
await _dbContext.SaveChangesAsync();
}
await trans.CommitAsync();
var categoryResult = Cast(category);
return new ApiResponse<Category>(categoryResult);
}
catch (DbException e)
{
await trans.RollbackAsync();
_logger.LogError(e, "新增/修改分类失败");
return new ApiResponse<Category>().Failed("数据库操作失败,请刷新重试");
}
}
public ApiResponse<List<Category>> GetCategoriesTree()
{
var qry = _dbContext.Categories
.AsNoTracking()
.Where(c => !c.Deleted)
.OrderBy(c => c.ParentId)
.ThenBy(c => c.Order)
.AsEnumerable();
var result = new ApiResponse<List<Category>>(ToTree(qry));
return result;
}
public async Task<ApiResponse> ResortCategoryAsync(ResortCategoryParams model)
{
var curr = await _dbContext.Categories
.FirstOrDefaultAsync(c => c.Id == model.Id && !c.Deleted);
if (null == curr)
return ApiResponse.Failed("此分类已不存在,请刷新重试");
var target = await _dbContext.Categories
.FirstOrDefaultAsync(c => c.Order == model.TargetOrder && !c.Deleted);
if (null == target)
return ApiResponse.Failed("目标位置分类已不存在,请刷新重试");
target.Order = curr.Order;
curr.Order = model.TargetOrder;
await _dbContext.SaveChangesAsync();
return ApiResponse.Succed();
}
#region private methods
private List<Category> ToTree(IEnumerable<EF.Models.Category> models)
{
Dictionary<int, Category> idDicts = [];
List<Category> categories = [];
foreach (var model in models)
{
Category node = Cast(model);
node.Children = [];
idDicts.Add(node.Id, node);
}
foreach (var d in idDicts)
{
if (d.Value.ParentId > 0)
idDicts[d.Value.ParentId].Children.Add(d.Value);
else
categories.Add(d.Value);
}
return categories;
}
private Category Cast(EF.Models.Category model)
{
return new()
{
Id = model.Id,
LogoUrl = string.IsNullOrWhiteSpace(model.Logo)
? ""
: _fileService.GetFileUrl(Models.UploadScences.Category, model.Logo),
Name = model.Name,
Order = model.Order,
ParentId = model.ParentId,
Children = []
};
}
private string BuildPath(string prefix, params int[] ids)
{
return string.Format("{0}/{1}/",
prefix.TrimEnd('/')
, string.Join('/', ids));
}
#endregion
}