From efdb99f8cecc4afb592afad79c761081d5d5cf22 Mon Sep 17 00:00:00 2001 From: lee <4766465@qq.com> Date: Wed, 18 Dec 2024 13:27:00 +0800 Subject: [PATCH] init --- yami-shop-api/src/main/java/com/yami/shop/api/controller/ProdController.java | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 285 insertions(+), 0 deletions(-) diff --git a/yami-shop-api/src/main/java/com/yami/shop/api/controller/ProdController.java b/yami-shop-api/src/main/java/com/yami/shop/api/controller/ProdController.java new file mode 100644 index 0000000..6852b8f --- /dev/null +++ b/yami-shop-api/src/main/java/com/yami/shop/api/controller/ProdController.java @@ -0,0 +1,285 @@ +/* + * 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); + } +} -- Gitblit v1.9.3