feat 添加商品接口

This commit is contained in:
lwh 2023-07-14 15:34:47 +08:00
parent ecc421b701
commit f8b50d29d4
13 changed files with 8420 additions and 7 deletions

View File

@ -23,8 +23,4 @@
<ProjectReference Include="..\ARW.Common\ARW.Common.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Dto\Api\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using ARW.Model.Models.Business.GoodsManager.Goodss;
namespace ARW.Model.Dto.Api.GoodsManager.Goodss
{
/// <summary>
/// 商品查询对象Api
///
/// @author lwh
/// @date 2023-07-09
/// </summary>
public class GoodsQueryDtoApi : PagerInfo
{
public long? ShopGuid { get; set; }
/// <summary>
/// 店铺经营类目
/// </summary>
public long? GoodsCategoryGuid { get; set; }
public string GoodsName { get; set; }
public string GoodsCoding { get; set; }
}
/// <summary>
/// 商品详情输入对象Api
///
/// @author lwh
/// @date 2023-07-09
/// </summary>
public class GoodsDtoApi
{
[Required(ErrorMessage = "商品Id不能为空")]
public long SpuId { get; set; }
}
}

View File

@ -0,0 +1,212 @@
using Newtonsoft.Json;
using OfficeOpenXml.Attributes;
using SqlSugar;
using System;
using System.Collections.Generic;
namespace ARW.Model.Vo.Api.GoodsManager.Goodss
{
/// <summary>
/// 商品展示对象Api
///
/// @author lwh
/// @date 2023-07-09
/// </summary>
public class GoodsVoApi
{
/// <summary>
/// 描述 : 商品Id
/// </summary>
[JsonConverter(typeof(ValueToStringConverter))]
[EpplusIgnore]
public long SpuId { get; set; }
/// <summary>
/// 描述 :店铺guid
/// </summary>
[JsonConverter(typeof(ValueToStringConverter))]
public long ShopGuid { get; set; }
/// <summary>
/// 描述 :店铺名称
/// </summary>
public string ShopName { get; set; }
/// <summary>
/// 描述 :商品类目guid
/// </summary>
[JsonConverter(typeof(ValueToStringConverter))]
public long CategoryIds { get; set; }
/// <summary>
/// 描述 :商品名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 描述 :编码
/// </summary>
public string GoodsCoding { get; set; }
/// <summary>
/// 描述 :主图视频
/// </summary>
public string Video { get; set; }
/// <summary>
/// 描述 :视频封面
/// </summary>
public string PrimaryImage { get; set; }
/// <summary>
/// 描述 :图片
/// </summary>
public string Images { get; set; }
/// <summary>
/// 描述 :价格(最低)
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// 描述 :划线价格(最低)
/// </summary>
public decimal OriginPrice { get; set; }
/// <summary>
/// 描述 :库存总量
/// </summary>
public int SpuStockQuantity { get; set; }
/// <summary>
/// 描述 :销量
/// </summary>
public int SoldNum { get; set; }
/// <summary>
/// 描述 :上下架状态(1上架 2下架)
/// </summary>
public int IsPutOnSale { get; set; }
}
/// <summary>
/// 商品详情展示对象Api
/// </summary>
public class GoodsApiDetailsVo
{
/// <summary>
/// 描述 : 商品Id
/// </summary>
[JsonConverter(typeof(ValueToStringConverter))]
[EpplusIgnore]
public long SpuId { get; set; }
/// <summary>
/// 描述 :店铺guid
/// </summary>
[JsonConverter(typeof(ValueToStringConverter))]
public long ShopGuid { get; set; }
/// <summary>
/// 描述 :商品类目guid
/// </summary>
[JsonConverter(typeof(ValueToStringConverter))]
public long CategoryIds { get; set; }
/// <summary>
/// 描述 :商品名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 描述 :编码
/// </summary>
public string GoodsCoding { get; set; }
/// <summary>
/// 描述 :主图视频
/// </summary>
public string Video { get; set; }
/// <summary>
/// 描述 :视频封面
/// </summary>
public string PrimaryImage { get; set; }
/// <summary>
/// 描述 :图片
/// </summary>
public string Images { get; set; }
/// <summary>
/// 描述 :价格(最低)
/// </summary>
public decimal MinSalePrice { get; set; }
/// <summary>
/// 描述 :价格(最高)
/// </summary>
public decimal MaxSalePrice { get; set; }
/// <summary>
/// 描述 :划线价格(最高)
/// </summary>
public decimal MaxLinePrice { get; set; }
/// <summary>
/// 描述 :库存总量
/// </summary>
public int SpuStockQuantity { get; set; }
/// <summary>
/// 描述 :销量
/// </summary>
public int SoldNum { get; set; }
/// <summary>
/// 描述 :上下架状态(1上架 2下架)
/// </summary>
public int IsPutOnSale { get; set; }
/// <summary>
/// 描述 :详情
/// </summary>
public string Desc { get; set; }
/// <summary>
/// 商品规格列表
/// </summary>
public List<GoodsSpecApiVo> SpecList { get; set; }
/// <summary>
/// 商品sku列表
/// </summary>
public List<GoosSkuApiVo> SkuList { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using Newtonsoft.Json;
using OfficeOpenXml.Attributes;
using SqlSugar;
using System;
using System.Collections.Generic;
namespace ARW.Model.Vo.Api.GoodsManager.Goodss
{
/// <summary>
/// 商品规格组展示对象Api
///
/// @author lwh
/// @date 2023-07-13
/// </summary>
public class GoodsSpecApiVo
{
/// <summary>
/// 描述 : 商品规格组Id
/// </summary>
public int SpecId { get; set; }
/// <summary>
/// 描述 :商品规格组名称
/// </summary>
public string Title { get; set; }
/// <summary>
/// 描述 : 商品规格列表
/// </summary>
public List<SpecValueApiVo> SpecValueList { get; set; }
}
}

View File

@ -0,0 +1,66 @@
using Newtonsoft.Json;
using OfficeOpenXml.Attributes;
using SqlSugar;
using System;
using System.Collections.Generic;
namespace ARW.Model.Vo.Api.GoodsManager.Goodss
{
/// <summary>
/// 商品sku展示对象Api
///
/// @author lwh
/// @date 2023-07-13
/// </summary>
public class GoosSkuApiVo
{
/// <summary>
/// 描述 : 商品SkuId
/// </summary>
public int SkuId { get; set; }
/// <summary>
/// 描述 : 商品规格图片
/// </summary>
public string SkuImage { get; set; }
/// <summary>
/// 描述 :商品规格详情
/// </summary>
public List<SkuSpecInfo> SpecInfo { get; set; }
/// <summary>
/// 描述 :商品sku价格
/// </summary>
public List<PriceInfo> PriceInfo { get; set; }
/// <summary>
/// 描述 : 商品sku库存总量
/// </summary>
public int Quantity { get; set; }
/// <summary>
/// 商品sku重量
/// </summary>
public decimal Weight { get; set; }
}
public class SkuSpecInfo
{
public int SpecId { get; set; }
public string SpecTitle { get; set; }
public int SpecValueId { get; set; }
public string SpecValue { get; set; }
}
public class PriceInfo
{
public int PriceType { get; set; }
public decimal Price { get; set; }
public string PriceTypeName { get; set; }
}
}

View File

@ -0,0 +1,41 @@
using Newtonsoft.Json;
using OfficeOpenXml.Attributes;
using SqlSugar;
using System;
using System.Collections.Generic;
namespace ARW.Model.Vo.Api.GoodsManager.Goodss
{
/// <summary>
/// 商品规格值展示对象Api
///
/// @author lwh
/// @date 2023-07-13
/// </summary>
public class SpecValueApiVo
{
/// <summary>
/// 描述 : 商品规格值Id
/// </summary>
public int SpecValueId { get; set; }
/// <summary>
/// 描述 : 商品规格组Id
/// </summary>
public int SpecId { get; set; }
/// <summary>
/// 描述 :商品规格值名称
/// </summary>
public string SpecValue { get; set; }
/// <summary>
/// 描述 : 商品规格值图片
/// </summary>
public string Image { get; set; }
}
}

View File

@ -0,0 +1,285 @@
using Infrastructure.Attribute;
using SqlSugar;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ARW.Model;
using ARW.Repository;
using ARW.Repository.Business.GoodsManager.Goodss;
using ARW.Service.Api.IBusinessService.GoodsManager.Goodss;
using ARW.Model.Dto.Api.GoodsManager.Goodss;
using ARW.Model.Models.Business.GoodsManager.Goodss;
using ARW.Model.Vo.Api.GoodsManager.Goodss;
using ARW.Model.Models.Business.ShopManager.Shops;
using ARW.Repository.Business.GoodsManager.GoodsSpecs.GoodsSpecRels;
using ARW.Repository.Business.GoodsManager.GoodsSpecs.Specs;
using ARW.Repository.Business.GoodsManager.GoodsSpecs.SpecValues;
using Newtonsoft.Json;
using Senparc.CO2NET.Extensions;
using ARW.Model.Models.Business.GoodsManager.GoodsSpecs.GoodsSkus;
using ARW.Repository.Business.GoodsManager.GoodsSpecs.GoodsSkus;
namespace ARW.Service.Api.BusinessService.GoodsManager.Goodss
{
/// <summary>
/// 商品接口实现类Api
///
/// @author lwh
/// @date 2023-07-09
/// </summary>
[AppService(ServiceType = typeof(IGoodsServiceApi), ServiceLifetime = LifeTime.Transient)]
public class GoodsServiceImplApi : BaseService<Goods>, IGoodsServiceApi
{
private readonly GoodsRepository _GoodsRepository;
private readonly GoodsSpecRelRepository _GoodsSpecRelRepository;
private readonly SpecRepository _SpecRepository;
private readonly SpecValueRepository _SpecValueRepository;
private readonly GoodsSkuRepository _GoodsSkuRepository;
public GoodsServiceImplApi(GoodsRepository GoodsRepository, GoodsSpecRelRepository goodsSpecRelRepository, SpecRepository specRepository, SpecValueRepository specValueRepository, GoodsSkuRepository goodsSkuRepository)
{
this._GoodsRepository = GoodsRepository;
_GoodsSpecRelRepository = goodsSpecRelRepository;
_SpecRepository = specRepository;
_SpecValueRepository = specValueRepository;
_GoodsSkuRepository = goodsSkuRepository;
}
#region Api接口代码
/// <summary>
/// 查询商品列表(Api)
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public async Task<PagedInfo<GoodsVoApi>> GetGoodsListApi(GoodsQueryDtoApi parm)
{
//开始拼装查询条件
var predicate = Expressionable.Create<Goods>();
predicate = predicate.AndIF(parm.ShopGuid != null, s => s.ShopGuid == parm.ShopGuid);
//predicate = predicate.AndIF(parm.GoodsCategoryGuid != null, s => s.GoodsCategoryGuid == parm.GoodsCategoryGuid);
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.GoodsName), s => s.GoodsName.Contains(parm.GoodsName));
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.GoodsCoding), s => s.GoodsCoding.Contains(parm.GoodsCoding));
var query = _GoodsRepository
.Queryable()
.LeftJoin<Shop>((s, c) => s.ShopGuid == c.ShopGuid)
.Where(predicate.ToExpression())
.WhereIF(parm.GoodsCategoryGuid != null, (s,c) => c.ShopBusinessCategoryGuid == parm.GoodsCategoryGuid)
.Where(s => s.GoodsShelfStatus == 1)
.OrderBy(s => s.GoodsSort, OrderByType.Desc)
.Select((s, c) => new GoodsVoApi
{
SpuId = s.GoodsGuid,
ShopGuid = s.ShopGuid,
ShopName = c.ShopName,
CategoryIds = s.ShopGoodsCategoryGuid,
Title = s.GoodsName,
GoodsCoding = s.GoodsCoding,
Video = s.GoodsMainImageVideo,
PrimaryImage = s.GoodsVideoCover,
Images = s.GoodsPicture,
Price = s.GoodsPriceLowest,
OriginPrice = s.GoodsDashedPriceLowest,
SpuStockQuantity = s.GoodsTotalInventory,
SoldNum = s.GoodsSalesInitial + s.GoodsSalesActual,
IsPutOnSale = s.GoodsShelfStatus,
});
return await query.ToPageAsync(parm);
}
/// <summary>
/// 查询商品详情(Api)
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public async Task<string> GetGoodsDetails(GoodsDtoApi parm)
{
var query = _GoodsRepository
.Queryable()
.Where(s => s.GoodsGuid == parm.SpuId)
.Select(s => new GoodsApiDetailsVo
{
SpuId = s.GoodsGuid,
ShopGuid = s.ShopGuid,
CategoryIds = s.ShopGoodsCategoryGuid,
Title = s.GoodsName,
GoodsCoding = s.GoodsCoding,
Video = s.GoodsMainImageVideo,
PrimaryImage = s.GoodsVideoCover,
Images = s.GoodsPicture,
MinSalePrice = s.GoodsPriceLowest,
MaxSalePrice = s.GoodsPriceHighest,
MaxLinePrice = s.GoodsDashedPriceHighest,
SpuStockQuantity = s.GoodsTotalInventory,
SoldNum = s.GoodsSalesInitial + s.GoodsSalesActual,
Desc = s.GoodsDetails,
IsPutOnSale = s.GoodsShelfStatus,
}).Take(1);
var json = await query.ToJsonAsync();
var data = await GetSpecList(json);
return data;
}
/// <summary>
/// 获取商品的规格组列表
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public async Task<string> GetSpecList(string json)
{
if (json != "[]")
{
json = json.Remove(0, 1);
json = json.Substring(0, json.Length - 1);
var data = JsonConvert.DeserializeObject<GoodsApiDetailsVo>(json);
var goodsSpecListVo = new List<GoodsSpecApiVo>();
var specIds = (await _GoodsSpecRelRepository.GetListAsync(s => s.GoodsGuid == data.SpuId))
.Select(item => item.SpecId)
.Distinct()
.ToList();
var specs = await _SpecRepository.GetListAsync(s => specIds.Contains(s.SpecId));
var specValueIds = (await _GoodsSpecRelRepository.GetListAsync(s => s.GoodsGuid == data.SpuId))
.Where(item => item.SpecValueId != 0)
.Select(item => item.SpecValueId)
.Distinct()
.ToList();
var specValues = await GetSpecValuesAsync(specValueIds);
foreach (var spec in specs)
{
var goodsSpecVo = new GoodsSpecApiVo
{
SpecId = spec.SpecId,
Title = spec.SpecName,
SpecValueList = new List<SpecValueApiVo>()
};
goodsSpecVo.SpecValueList.AddRange(specValues.Where(sv => sv.SpecId == spec.SpecId));
goodsSpecListVo.Add(goodsSpecVo);
}
// 获取Sku列表
var skuList = await _GoodsSkuRepository.GetListAsync(s => s.GoodsGuid == data.SpuId);
data.SkuList = await GetSkuListWithSpecValuesAsync(skuList);
data.SpecList = goodsSpecListVo;
json = data.ToJson();
}
return json;
}
/// <summary>
/// 获取商品规格值列表
/// </summary>
/// <param name="specValueIds"></param>
/// <returns></returns>
private async Task<List<SpecValueApiVo>> GetSpecValuesAsync(List<int> specValueIds)
{
var specValues = await _SpecValueRepository.GetListAsync(sv => specValueIds.Contains(sv.SpecValueId));
return specValues.Select(sv => new SpecValueApiVo
{
SpecValueId = sv.SpecValueId,
SpecId = sv.SpecId,
SpecValue = sv.SpecValueName,
}).ToList();
}
/// <summary>
/// 获取商品sku列表
/// </summary>
/// <param name="skuList"></param>
/// <returns></returns>
private async Task<List<GoosSkuApiVo>> GetSkuListWithSpecValuesAsync(List<GoodsSku> skuList)
{
var resList = new List<GoosSkuApiVo>();
var specValueIds = skuList.SelectMany(sku => new[] { sku.SpecValueId, sku.SpecSecondValueId, sku.SpecThirdValueId })
.Distinct()
.Where(id => id != 0)
.ToList();
// sku所属商品规格
var specValues = await GetSpecValuesAsync(specValueIds);
var addedSpecValueIds = new HashSet<int>();
foreach (var item in skuList)
{
var list = new List<SkuSpecInfo>();
await AddSkuSpecInfo(item.SpecValueId);
await AddSkuSpecInfo(item.SpecSecondValueId);
await AddSkuSpecInfo(item.SpecThirdValueId);
async Task AddSkuSpecInfo(int specValueId)
{
if (specValueId != 0)
{
//addedSpecValueIds.Add(specValueId);
var sku = specValues.FirstOrDefault(sv => sv.SpecValueId == specValueId);
var spec = await _SpecRepository.GetFirstAsync(s => s.SpecId == sku.SpecId);
var skuSpecInfo = new SkuSpecInfo
{
SpecId = sku.SpecId,
SpecTitle = spec.SpecName,
SpecValueId = sku.SpecValueId,
SpecValue = sku.SpecValue
};
list.Add(skuSpecInfo);
}
}
// sku价格
var skuPriceInfoList = new List<PriceInfo>();
var skuPriceInfo1 = new PriceInfo
{
PriceType = 1,
Price = item.GoodsSkuPrice,
PriceTypeName = "销售价格"
};
skuPriceInfoList.Add(skuPriceInfo1);
if (item.GoodsSkuLinePrice != 0)
{
var skuPriceInfo2 = new PriceInfo
{
PriceType = 2,
Price = item.GoodsSkuLinePrice,
PriceTypeName = "划线价格"
};
skuPriceInfoList.Add(skuPriceInfo2);
}
var skuVo = new GoosSkuApiVo
{
SkuId = item.GoodsSkuId,
SkuImage = item.GoodsSkuImg,
SpecInfo = list,
PriceInfo = skuPriceInfoList,
Quantity = item.GoodsSkuStockNum,
Weight = item.GoodsSkuWeight
};
resList.Add(skuVo);
}
return resList;
}
#endregion
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ARW.Model;
using ARW.Model.Dto.Api.GoodsManager.Goodss;
using ARW.Model.Models.Business.GoodsManager.Goodss;
using ARW.Model.Vo.Api.GoodsManager.Goodss;
namespace ARW.Service.Api.IBusinessService.GoodsManager.Goodss
{
/// <summary>
/// 商品接口类Api
///
/// @author lwh
/// @date 2023-07-09
/// </summary>
public interface IGoodsServiceApi : IBaseService<Goods>
{
/// <summary>
/// 获取商品分页列表(Api)
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
Task<PagedInfo<GoodsVoApi>> GetGoodsListApi(GoodsQueryDtoApi parm);
/// <summary>
/// 获取商品详情(Api)
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
Task<string> GetGoodsDetails(GoodsDtoApi parm);
}
}

View File

@ -33,7 +33,7 @@ namespace ARW.Service.Business.BusinessService.GoodsManager.GoodsCategorys
this._GoodsCategoryRepository = GoodsCategoryRepository;
}
#region
#region
/// <summary>

View File

@ -24,7 +24,7 @@ namespace ARW.WebApi.Controllers.Api.GoodsManager.GoodsCategorys
/// @author lwh
/// @date 2023-07-08
/// </summary>
[Verify]
//[Verify]
[Route("api/[controller]")]
public class GoodsCategoryApiController : BaseController
{

View File

@ -0,0 +1,79 @@
using Infrastructure;
using Infrastructure.Attribute;
using Infrastructure.Enums;
using Infrastructure.Model;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using ARW.Admin.WebApi.Extensions;
using ARW.Admin.WebApi.Filters;
using ARW.Common;
using ARW.Admin.WebApi.Controllers;
using ARW.Model.Dto.Api.GoodsManager.Goodss;
using ARW.Service.Api.IBusinessService.GoodsManager.Goodss;
using ARW.Model.Models.Business.GoodsManager.Goodss;
using ARW.Model.Vo.Api.GoodsManager.Goodss;
using Microsoft.AspNetCore.Authorization;
using Geocoding;
namespace ARW.WebApi.Controllers.Api.GoodsManager.Goodss
{
/// <summary>
/// 商品控制器Api
///
/// @author lwh
/// @date 2023-07-09
/// </summary>
//[Verify]
[Route("api/[controller]")]
public class GoodsApiController : BaseController
{
private readonly IGoodsServiceApi _GoodsServiceApi;
/// <summary>
/// 依赖注入
/// </summary>
/// <param name="GoodsServiceApi">商品商品Api服务</param>
public GoodsApiController(IGoodsServiceApi GoodsServiceApi)
{
_GoodsServiceApi = GoodsServiceApi;
}
/// <summary>
/// 获取商品列表(Api)
/// </summary>
/// <param name="parm">查询参数</param>
/// <returns></returns>
[HttpGet("getGoodsList")]
public async Task<IActionResult> GetGoodsListApi([FromQuery] GoodsQueryDtoApi parm)
{
var res = await _GoodsServiceApi.GetGoodsListApi(parm);
return SUCCESS(res);
}
/// <summary>
/// 获取Goods详情(Api)
/// </summary>
/// <param name="parm">查询参数</param>
/// <returns></returns>
[HttpGet("getGoodsDetails")]
public async Task<IActionResult> GetGoodsDetails([FromQuery] GoodsDtoApi parm)
{
//if (parm == null) throw new CustomException("参数错误!");
var res = await _GoodsServiceApi.GetGoodsDetails(parm);
if (res != "[]")
{
var data = res.FromJSON<GoodsApiDetailsVo>();
return SUCCESS(data);
}
else
{
return SUCCESS(res);
}
}
}
}

View File

@ -129,7 +129,7 @@ $end
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public Task<string> Get${replaceDto.ModelTypeName}Details(${replaceDto.ModelTypeName}DtoApi parm)
public async Task<string> Get${replaceDto.ModelTypeName}Details(${replaceDto.ModelTypeName}DtoApi parm)
{
var query = _${replaceDto.ModelTypeName}Repository

7622
document/shop_template.sql Normal file

File diff suppressed because it is too large Load Diff