using Microsoft.EntityFrameworkCore; using StopShopping.EF; using StopShopping.Services.Models.Req; using StopShopping.Services.Models.Resp; namespace StopShopping.Services.Implementions; public class ProductService : IProductService { public ProductService( StopShoppingContext dbContext, IClaimsService claimsService, IFileService fileService, ISerialNoGenerator serialNoGenerator) { _dbContext = dbContext; _claimsService = claimsService; _fileService = fileService; _serilNoGenerator = serialNoGenerator; } private readonly StopShoppingContext _dbContext; private readonly IClaimsService _claimsService; private readonly IFileService _fileService; private readonly ISerialNoGenerator _serilNoGenerator; public ApiResponse Detail(ProductIdParams model) { var detail = _dbContext.Products .AsNoTracking() .Where(p => p.Id == model.ProductId && !p.Deleted) .Include(p => p.Category) .Select(Cast) .FirstOrDefault(); if (null == detail) return new ApiResponse().Failed("商品已不存在,请刷新重试"); return new ApiResponse(detail); } public async Task>> SearchAsync(ProductSearchParms model) { var userId = _claimsService.GetCurrentUserId(); var qry = _dbContext.Products .AsNoTracking() .Include(p => p.Category) .Where(p => !p.Deleted); if (userId.HasValue) qry = qry.Where(p => p.UserId == userId); if (model.CategoryId > 0) { var categoryPath = (await _dbContext.Categories .FirstOrDefaultAsync(c1 => c1.Id == model.CategoryId)) ?.Path ?? ""; qry = qry.Where(p => _dbContext.Categories .Where(c => c.Path.StartsWith(categoryPath)) .Select(c => c.Id) .Contains(p.CategoryId)); } if (!string.IsNullOrWhiteSpace(model.Keyword)) qry = qry.Where(p => p.Name.Contains(model.Keyword) || (p.Description != null && p.Description.Contains(model.Keyword))); var orderedQry = WithOrderBys(qry, model.OrderBys); var result = await orderedQry! .Select(Cast) .ToAsyncEnumerable() .ToPagedAsync(model.PageIndex, model.PageSize); return new ApiResponse>(result); } public async Task EditAsync(EditProductParams model) { var userId = _claimsService.GetCurrentUserId()!.Value; EF.Models.Product? product = null; if (model.Id > 0) { product = await _dbContext.Products .FirstOrDefaultAsync(p => p.Id == model.Id.Value && p.UserId == userId && !p.Deleted); if (null == product) return ApiResponse.Failed("商品已不存在,请刷新重试"); } else { product = new() { SerialNo = _serilNoGenerator.GenerateProductNo(), UserId = userId, Logo = string.IsNullOrWhiteSpace(model.LogoName) ? Consts.DEFAULT_PRODUCT : model.LogoName }; await _dbContext.Products.AddAsync(product); } product.CategoryId = model.CategoryId; product.Description = model.Description; product.Detail = model.Detail; product.MinimumUnit = model.MinimumUnit ?? ""; product.Name = model.Name ?? ""; product.UnitPrice = model.UnitPrice; await _dbContext.SaveChangesAsync(); return ApiResponse.Succed(); } public async Task DeleteAsync(ProductIdParams model) { var userId = _claimsService.GetCurrentUserId()!.Value; var product = await _dbContext.Products .FirstOrDefaultAsync(p => p.Id == model.ProductId && p.UserId == userId && !p.Deleted); if (null == product) return ApiResponse.Failed("此商品已不存在,请刷新重试"); product.Deleted = true; await _dbContext.SaveChangesAsync(); return ApiResponse.Succed(); } #region private methods private IOrderedQueryable? WithOrderBys(IQueryable qry, IEnumerable orderBys) { IOrderedQueryable? orderedQry = null; foreach (var orderby in orderBys) { if (null == orderedQry) orderedQry = orderby switch { ProductOrderBys.CreateTime => qry.OrderBy(p => p.CreateTime), ProductOrderBys.CreateTimeDesc => qry.OrderByDescending(p => p.CreateTime), ProductOrderBys.Category => qry.OrderBy(p => p.Category), ProductOrderBys.CategoryDesc => qry.OrderByDescending(p => p.Category), ProductOrderBys.SoldAmount => qry.OrderBy(p => p.SoldAmount), ProductOrderBys.SoldAmountDesc => qry.OrderByDescending(p => p.SoldAmount), _ => qry.OrderBy(p => p.CreateTime), }; else orderedQry = orderby switch { ProductOrderBys.CreateTime => orderedQry.ThenBy(p => p.CreateTime), ProductOrderBys.CreateTimeDesc => orderedQry.ThenByDescending(p => p.CreateTime), ProductOrderBys.Category => orderedQry.ThenBy(p => p.Category), ProductOrderBys.CategoryDesc => orderedQry.ThenByDescending(p => p.Category), ProductOrderBys.SoldAmount => orderedQry.ThenBy(p => p.SoldAmount), ProductOrderBys.SoldAmountDesc => orderedQry.ThenByDescending(p => p.SoldAmount), _ => orderedQry.ThenBy(p => p.CreateTime), }; } return orderedQry; } private T Cast(EF.Models.Product product) where T : Product, new() { var result = new T { CategoryName = product.Category.Name, CreateTime = product.CreateTime.ToFormatted(), Description = product.Description, Id = product.Id, LogoUrl = _fileService.GetFileUrl(Models.UploadScences.Product, product.Logo), MinimumUnit = product.MinimumUnit, Name = product.Name, UnitPrice = product.UnitPrice, SoldAmount = product.SoldAmount, }; if (result is ProductInfo) { (result as ProductInfo)!.CategoryId = product.CategoryId; (result as ProductInfo)!.Detail = product.Detail; } return result; } #endregion }