/*
|
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
|
*
|
* https://www.mall4j.com/
|
*
|
* 未经允许,不可做商业用途!
|
*
|
* 版权所有,侵权必究!
|
*/
|
package com.yami.shop.api.controller;
|
|
import cn.hutool.core.collection.CollUtil;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.yami.shop.bean.app.dto.*;
|
import com.yami.shop.bean.app.vo.ProductVO;
|
import com.yami.shop.bean.enums.ProdStatusEnums;
|
import com.yami.shop.bean.enums.ProdType;
|
import com.yami.shop.bean.enums.ShopStatus;
|
import com.yami.shop.bean.event.CheckAddrEvent;
|
import com.yami.shop.bean.event.LoadProdActivistEvent;
|
import com.yami.shop.bean.event.ProcessActivityProdPriceEvent;
|
import com.yami.shop.bean.model.*;
|
import com.yami.shop.bean.param.EsProductParam;
|
import com.yami.shop.bean.param.ProductParam;
|
import com.yami.shop.bean.vo.search.EsProductSearchVO;
|
import com.yami.shop.bean.vo.search.ProductSearchVO;
|
import com.yami.shop.common.config.Constant;
|
import com.yami.shop.common.exception.YamiShopBindException;
|
import com.yami.shop.common.i18n.I18nMessage;
|
import com.yami.shop.common.response.ServerResponseEntity;
|
import com.yami.shop.common.util.Json;
|
import com.yami.shop.common.util.PageParam;
|
import com.yami.shop.delivery.common.model.SameCity;
|
import com.yami.shop.delivery.common.service.SameCityService;
|
import com.yami.shop.search.common.param.EsPageParam;
|
import com.yami.shop.search.common.service.SearchProductService;
|
import com.yami.shop.search.common.vo.EsPageVO;
|
import com.yami.shop.security.api.model.YamiUser;
|
import com.yami.shop.security.api.util.SecurityUtils;
|
import com.yami.shop.security.common.bo.UserInfoInTokenBO;
|
import com.yami.shop.security.common.util.AuthUserContext;
|
import com.yami.shop.service.*;
|
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameters;
|
import io.swagger.v3.oas.annotations.Operation;
|
import ma.glasnost.orika.MapperFacade;
|
import org.springdoc.api.annotations.ParameterObject;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.context.ApplicationContext;
|
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RestController;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* @author LGH
|
*/
|
@RestController
|
@RequestMapping("/prod")
|
@Tag(name = "商品接口")
|
public class ProdController {
|
|
@Autowired
|
private ProductService prodService;
|
@Autowired
|
private CategoryService categoryService;
|
@Autowired
|
private MapperFacade mapperFacade;
|
@Autowired
|
private SameCityService sameCityService;
|
@Autowired
|
private ApplicationContext applicationContext;
|
@Autowired
|
private SkuService skuService;
|
@Autowired
|
private ProdCommService prodCommService;
|
@Autowired
|
private ShopDetailService shopDetailService;
|
@Autowired
|
private ProdParameterService prodParameterService;
|
@Autowired
|
private SearchProductService searchProductService;
|
|
@GetMapping("/prodInfo")
|
@Operation(summary = "商品详情信息" , description = "根据商品ID(prodId)获取商品信息")
|
@Parameter(name = "prodId", description = "商品ID" , required = true)
|
public ServerResponseEntity<ProductVO> prodInfo(Long prodId, String userId) {
|
Integer dbLang = I18nMessage.getDbLang();
|
Product product = prodService.getProductInfo(prodId, dbLang);
|
if (product == null || product.getStatus() != 1) {
|
// 商品已下线
|
throw new YamiShopBindException("yami.product.off.shelves");
|
}
|
// 检查店铺是否处于营业状态
|
checkShopStatusIsOpen(product);
|
// 启用的sku列表
|
List<Sku> skuList = skuService.listPutOnSkuAndSkuStock(prodId, dbLang);
|
product.setSkuList(skuList);
|
ProductVO productVO = mapperFacade.map(product, ProductVO.class);
|
if(Objects.equals(productVO.getProdType(), ProdType.PROD_TYPE_ACTIVE.value()) || (Objects.nonNull(productVO.getMold()) && productVO.getMold() == 1)){
|
productVO.setIsDelivery(true);
|
}else{
|
// 判断用户默认地址是否在配送区域内
|
applicationContext.publishEvent(new CheckAddrEvent(0L, userId, productVO, null));
|
}
|
// 如果是积分商品, 所有数据已经获取完成了
|
if (Objects.equals(productVO.getProdType(), ProdType.PROD_TYPE_SCORE.value())) {
|
return ServerResponseEntity.success(productVO);
|
}
|
// 发送事件,获取商品可用的正在开播直播间、商品套餐、秒杀、团购、积分商品信息
|
applicationContext.publishEvent(new LoadProdActivistEvent(prodId, productVO, product.getProdType()));
|
// 普通商品有多种物流,需要加载物流模板信息
|
// if (Objects.equals(productVO.getProdType(), ProdType.PROD_TYPE_NORMAL.value())) {
|
loadDeliveryMode(product.getDeliveryMode(), productVO);
|
// }
|
// 商品参数列表
|
List<ProdParameter> prodParameters = prodParameterService.listParameter(prodId, I18nMessage.getDbLang());
|
productVO.setProdParameterList(prodParameters);
|
return ServerResponseEntity.success(productVO);
|
}
|
|
@GetMapping("/skuList")
|
@Operation(summary = "sku信息" , description = "根据商品ID(prodId)单独获取sku信息")
|
@Parameter(name = "prodId", description = "商品ID" , required = true)
|
public ServerResponseEntity<List<SkuDto>> skuList(@RequestParam("prodId") Long prodId) {
|
return ServerResponseEntity.success(skuService.getProdDetailSkuInfo(prodId));
|
}
|
|
@GetMapping("/isStatus")
|
@Operation(summary = "校验商品是否下架" , description = "根据商品ID(prodId)校验商品是否下架")
|
@Parameter(name = "prodId", description = "商品ID" , required = true)
|
public ServerResponseEntity<Boolean> isStatus(Long prodId) {
|
Product product = prodService.getProductByProdId(prodId, I18nMessage.getDbLang());
|
if (product == null || product.getStatus() != 1) {
|
return ServerResponseEntity.success(false);
|
}
|
return ServerResponseEntity.success(true);
|
}
|
|
@GetMapping("/listProdByIdsAndType")
|
@Operation(summary = "获取商品信息" , description = "根据商品ids获取商品信息")
|
public ServerResponseEntity<List<ProductDto>> listProdByIdsAndType(@ParameterObject ApiProdDto apiProdDto) {
|
ProductParam productParam = mapperFacade.map(apiProdDto, ProductParam.class);
|
apiProdDto.setLang(I18nMessage.getDbLang());
|
apiProdDto.setStatus(ProdStatusEnums.NORMAL.getValue());
|
List<Product> products = prodService.listProdByIdsAndType(productParam);
|
processActivityProdPrice(productParam, products);
|
List<ProductDto> productDtos = mapperFacade.mapAsList(products, ProductDto.class);
|
return ServerResponseEntity.success(productDtos);
|
}
|
|
/**
|
* 处理下活动商品的价格
|
*
|
* @param product 筛选参数
|
* @param products 商品列表
|
*/
|
private void processActivityProdPrice(ProductParam product, List<Product> products) {
|
Map<Integer, List<Product>> prodMap = products.stream().collect(Collectors.groupingBy(Product::getProdType));
|
if (prodMap.containsKey(ProdType.PROD_TYPE_SECKILL.value())) {
|
applicationContext.publishEvent(new ProcessActivityProdPriceEvent(product, prodMap.get(ProdType.PROD_TYPE_SECKILL.value())));
|
}
|
|
if (prodMap.containsKey(ProdType.PROD_TYPE_GROUP.value())) {
|
applicationContext.publishEvent(new ProcessActivityProdPriceEvent(product, prodMap.get(ProdType.PROD_TYPE_GROUP.value())));
|
}
|
}
|
|
@GetMapping("/prodCommData")
|
@Operation(summary = "返回商品评论数据(好评率 好评数量 中评数 差评数)" , description = "根据商品id获取")
|
@Parameter(name = "prodId", description = "商品id" , required = true)
|
public ServerResponseEntity<ProdCommDataDto> getProdCommData(Long prodId) {
|
return ServerResponseEntity.success(prodCommService.getProdCommDataByProdId(prodId));
|
}
|
|
@GetMapping("/prodCommPageByProd")
|
@Operation(summary = "根据商品返回评论分页数据" , description = "传入商品id和页码")
|
@Parameters({
|
@Parameter(name = "prodId", description = "商品id" , required = true),
|
@Parameter(name = "evaluate", description = "-1或null 全部,0好评 1中评 2差评 3有图" , required = true),
|
})
|
public ServerResponseEntity<IPage<ProdCommDto>> getProdCommPageByProdId(PageParam page, Long prodId, Integer evaluate) {
|
return ServerResponseEntity.success(prodCommService.getProdCommDtoPageByProdId(page, prodId, evaluate));
|
}
|
|
/**
|
* 用户未登录情况下的商品推荐
|
* @param page
|
* @param productParam
|
* @return
|
*/
|
@GetMapping("/recommendList")
|
@Operation(summary = "推荐商品列表" , description = "根据商品ID(prodId)获取商品信息")
|
public ServerResponseEntity<EsPageVO<EsProductSearchVO>> recommendList(PageParam page, @ParameterObject ProductParam productParam) {
|
EsProductParam esProductParam = new EsProductParam();
|
if (Objects.isNull(productParam.getProdType())) {
|
esProductParam.setProdType(ProdType.PROD_TYPE_NORMAL.value());
|
}
|
Long primaryCategoryId = null;
|
List<Category> categoryList = categoryService.getCategoryAndParent(productParam.getCategoryId());
|
if (CollUtil.isNotEmpty(categoryList)) {
|
primaryCategoryId = categoryList.get(0).getCategoryId();
|
}
|
esProductParam.setPrimaryCategoryId(primaryCategoryId);
|
//如果有商品id则过滤掉
|
if (Objects.nonNull(productParam.getProdId())) {
|
List<Long> prodIds = new ArrayList<>();
|
prodIds.add(productParam.getProdId());
|
esProductParam.setSpuIdsExclude(prodIds);
|
}
|
EsPageParam esPageParam = new EsPageParam();
|
esPageParam.setCurrent((int) page.getCurrent());
|
esPageParam.setSize((int) page.getSize());
|
EsPageVO<EsProductSearchVO> productPage = searchProductService.page(esPageParam, esProductParam, Boolean.FALSE);
|
List<ProductSearchVO> products = productPage.getRecords().get(0).getProducts();
|
long current = page.getCurrent();
|
long size = page.getSize();
|
int spuNum = products.size();
|
// 推荐商品的数量不足时,查询额外的商品进行填充
|
if (Objects.equals(current , 1L) && size > spuNum) {
|
esPageParam.setSize(Math.toIntExact(size - spuNum));
|
esPageParam.setCurrent(1);
|
// 查询该分类以外的商品
|
esProductParam.setPrimaryCategoryId(null);
|
esProductParam.setNotPrimaryCategoryId(primaryCategoryId);
|
EsPageVO<EsProductSearchVO> subProductPage = searchProductService.page(esPageParam, esProductParam, Boolean.FALSE);
|
for (EsProductSearchVO productSearchVO : subProductPage.getRecords()) {
|
if (CollUtil.isNotEmpty(productSearchVO.getProducts())) {
|
products.addAll(productSearchVO.getProducts());
|
}
|
}
|
productPage.setTotal((long) products.size());
|
productPage.setPages(productPage.getTotal() > 0 ? (int)page.getCurrent() : 0);
|
}
|
return ServerResponseEntity.success(productPage);
|
}
|
|
private void checkShopStatusIsOpen(Product product) {
|
// 积分商品的平台店铺不需要检验
|
if (Objects.equals(product.getShopId(), Constant.PLATFORM_SHOP_ID)) {
|
return;
|
}
|
Date now = new Date();
|
ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(product.getShopId());
|
if (Objects.equals(shopDetail.getShopStatus(), ShopStatus.OPEN.value())) {
|
return;
|
}
|
product.setShopName(shopDetail.getShopName());
|
if (Objects.equals(shopDetail.getShopStatus(), ShopStatus.OFFLINE.value()) || Objects.equals(shopDetail.getShopStatus(), ShopStatus.OFFLINE_AUDIT.value())) {
|
throw new YamiShopBindException("店铺已下线");
|
}
|
if (Objects.equals(shopDetail.getShopStatus(), ShopStatus.STOP.value())) {
|
if (now.compareTo(shopDetail.getContractStartTime()) < 0) {
|
throw new YamiShopBindException("店铺未开始营业");
|
} else {
|
throw new YamiShopBindException("店铺已停止营业");
|
}
|
}
|
throw new YamiShopBindException("店铺状态异常");
|
}
|
|
/**
|
* 加载商品物流模板
|
* @param deliveryMode
|
* @param productVO
|
*/
|
private void loadDeliveryMode(String deliveryMode, ProductVO productVO) {
|
// 物流模板
|
Product.DeliveryModeVO deliveryModeVO = Json.parseObject(deliveryMode, Product.DeliveryModeVO.class);
|
SameCity sameCity = sameCityService.getSameCityByShopId(productVO.getShopId());
|
// 如果同城配送是关闭了的,前端就不需要显示同城配送了
|
if (Objects.isNull(sameCity) || !Objects.equals(1, sameCity.getStatus()) || Objects.isNull(deliveryModeVO.getHasCityDelivery())) {
|
deliveryModeVO.setHasCityDelivery(false);
|
}
|
if (deliveryModeVO.getHasCityDelivery() != null && deliveryModeVO.getHasCityDelivery() && Objects.nonNull(sameCity)) {
|
productVO.setStartDeliveryFee(sameCity.getStartingFee());
|
}
|
productVO.setDeliveryModeVO(deliveryModeVO);
|
}
|
}
|