mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 02:08:43 +08:00 
			
		
		
		
	完善 App 商品搜索的逻辑
This commit is contained in:
		| @@ -1,8 +1,18 @@ | ||||
| ### 获得订单交易的分页 TODO | ||||
| ### 获得订单交易的分页(默认) | ||||
| GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10 | ||||
| Authorization: Bearer {{appToken}} | ||||
| tenant-id: {{appTenentId}} | ||||
|  | ||||
| ### 获得订单交易的分页(价格) | ||||
| GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10&sortField=price&sortAsc=true | ||||
| Authorization: Bearer {{appToken}} | ||||
| tenant-id: {{appTenentId}} | ||||
|  | ||||
| ### 获得订单交易的分页(销售) | ||||
| GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10&sortField=salesCount&sortAsc=true | ||||
| Authorization: Bearer {{appToken}} | ||||
| tenant-id: {{appTenentId}} | ||||
|  | ||||
| ### 获得商品 SPU 明细 | ||||
| GET {{appApi}}/product/spu/get-detail?id=4 | ||||
| tenant-id: {{appTenentId}} | ||||
|   | ||||
| @@ -49,8 +49,8 @@ public class AppProductSpuController { | ||||
|     @GetMapping("/page") | ||||
|     @Operation(summary = "获得商品 SPU 分页") | ||||
|     public CommonResult<PageResult<AppProductSpuPageItemRespVO>> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { | ||||
|         PageResult<ProductSpuDO> pageResult = productSpuService.getSpuPage(pageVO, ProductSpuStatusEnum.ENABLE.getStatus()); | ||||
|         return success(ProductSpuConvert.INSTANCE.convertPage02(pageResult)); | ||||
|         PageResult<ProductSpuDO> pageResult = productSpuService.getSpuPage(pageVO); | ||||
|         return success(ProductSpuConvert.INSTANCE.convertPageForGetSpuPage(pageResult)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-detail") | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.product.controller.app.spu.vo; | ||||
|  | ||||
| import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||||
| import io.swagger.v3.oas.annotations.media.Schema; | ||||
| import lombok.Data; | ||||
|  | ||||
| @@ -15,21 +16,24 @@ public class AppProductSpuPageItemRespVO { | ||||
|     private Long id; | ||||
|  | ||||
|     @Schema(description = "商品名称", required = true, example = "芋道") | ||||
|     @NotEmpty(message = "商品名称不能为空") | ||||
|     private String name; | ||||
|  | ||||
|     @Schema(description = "分类编号", required = true) | ||||
|     @NotNull(message = "分类编号不能为空") | ||||
|     private Long categoryId; | ||||
|  | ||||
|     @Schema(description = "商品图片的数组", required = true) | ||||
|     private List<String> picUrls; | ||||
|     @Schema(description = "商品封面图", required = true) | ||||
|     private String picUrl; | ||||
|  | ||||
|     @Schema(description = " 最小价格,单位使用:分", required = true, example = "1024") | ||||
|     private Integer minPrice; | ||||
|     @Schema(description = "商品轮播图", required = true) | ||||
|     private List<String> sliderPicUrls; | ||||
|  | ||||
|     @Schema(description = "最大价格,单位使用:分", required = true, example = "1024") | ||||
|     private Integer maxPrice; | ||||
|     @Schema(description = "商品价格,单位使用:分", required = true, example = "1024") | ||||
|     private Integer price; | ||||
|  | ||||
|     // ========== SKU 相关字段 ========= | ||||
|  | ||||
|     @Schema(description = "库存", required = true, example = "666") | ||||
|     private Integer stock; | ||||
|  | ||||
|     // ========== 统计相关字段 ========= | ||||
|  | ||||
|   | ||||
| @@ -19,18 +19,23 @@ public class AppProductSpuPageReqVO extends PageParam { | ||||
|     public static final String SORT_FIELD_PRICE = "price"; | ||||
|     public static final String SORT_FIELD_SALES_COUNT = "salesCount"; | ||||
|  | ||||
|     public static final String RECOMMEND_TYPE_HOT = "hot"; | ||||
|  | ||||
|     @Schema(description = "分类编号", example = "1") | ||||
|     private Long categoryId; | ||||
|  | ||||
|     @Schema(description = "关键字", example = "好看") | ||||
|     private String keyword; | ||||
|  | ||||
|     @Schema(description = "排序字段", example = "price") // 参见 AppSpuPageReqVO.SORT_FIELD_XXX 常量 | ||||
|     @Schema(description = "排序字段", example = "price") // 参见 AppProductSpuPageReqVO.SORT_FIELD_XXX 常量 | ||||
|     private String sortField; | ||||
|  | ||||
|     @Schema(description = "排序方式", example = "true") | ||||
|     private Boolean sortAsc; | ||||
|  | ||||
|     @Schema(description = "推荐类型", example = "hot") // 参见 AppProductSpuPageReqVO.RECOMMEND_TYPE_XXX 常亮 | ||||
|     private String recommendType; | ||||
|  | ||||
|     @AssertTrue(message = "排序字段不合法") | ||||
|     @JsonIgnore | ||||
|     public boolean isSortFieldValid() { | ||||
|   | ||||
| @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||||
| import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | ||||
| import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.Named; | ||||
| import org.mapstruct.factory.Mappers; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| @@ -75,8 +76,6 @@ public interface ProductSpuConvert { | ||||
|     List<AppProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> skus); | ||||
|     AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue); | ||||
|  | ||||
|     PageResult<AppProductSpuPageItemRespVO> convertPage02(PageResult<ProductSpuDO> page); | ||||
|  | ||||
|     default ProductSpuDetailRespVO convert03(ProductSpuDO spu, List<ProductSkuDO> skus, | ||||
|                                              List<ProductPropertyValueDetailRespBO> propertyValues) { | ||||
|         ProductSpuDetailRespVO spuVO = convert03(spu); | ||||
| @@ -105,4 +104,14 @@ public interface ProductSpuConvert { | ||||
|     List<ProductSpuDetailRespVO.Sku> convertList04(List<ProductSkuDO> skus); | ||||
|     ProductPropertyValueDetailRespVO convert04(ProductPropertyValueDetailRespBO propertyValue); | ||||
|  | ||||
|     // ========== 用户 App 相关 ========== | ||||
|  | ||||
|     default PageResult<AppProductSpuPageItemRespVO> convertPageForGetSpuPage(PageResult<ProductSpuDO> page) { | ||||
|         // 累加虚拟销量 | ||||
|         page.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount())); | ||||
|         // 然后进行转换 | ||||
|         return convertPageForGetSpuPage0(page); | ||||
|     } | ||||
|     PageResult<AppProductSpuPageItemRespVO> convertPageForGetSpuPage0(PageResult<ProductSpuDO> page); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,15 @@ | ||||
| package cn.iocoder.yudao.module.product.dal.mysql.spu; | ||||
|  | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||||
| import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; | ||||
| import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; | ||||
| import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; | ||||
| import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | ||||
| import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | ||||
| import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||
| import org.apache.ibatis.annotations.Mapper; | ||||
|  | ||||
| @@ -46,16 +50,28 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> { | ||||
|                 .orderByDesc(ProductSpuDO::getSort)); | ||||
|     } | ||||
|  | ||||
|     default PageResult<ProductSpuDO> selectPage(AppProductSpuPageReqVO pageReqVO, Integer status) { | ||||
|     /** | ||||
|      * 获得商品 SPU 分页,提供给用户 App 使用 | ||||
|      */ | ||||
|     default PageResult<ProductSpuDO> selectPage(AppProductSpuPageReqVO pageReqVO, Set<Long> categoryIds) { | ||||
|         LambdaQueryWrapperX<ProductSpuDO> query = new LambdaQueryWrapperX<ProductSpuDO>() | ||||
|                 .eqIfPresent(ProductSpuDO::getCategoryId, pageReqVO.getCategoryId()) | ||||
|                 .eqIfPresent(ProductSpuDO::getStatus, status); | ||||
|                 .likeIfPresent(ProductSpuDO::getName, pageReqVO.getKeyword()) // 关键字匹配,目前只匹配商品名 | ||||
|                 .inIfPresent(ProductSpuDO::getCategoryId, categoryIds); // 分类 | ||||
|         query.eq(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()) // 上架状态 | ||||
|                 .gt(ProductSpuDO::getStock, 0); // 有库存 | ||||
|         // 推荐类型的过滤条件 | ||||
|         if (ObjUtil.equal(pageReqVO.getRecommendType(), AppProductSpuPageReqVO.RECOMMEND_TYPE_HOT)) { | ||||
|             query.eq(ProductSpuDO::getRecommendHot, true); | ||||
|         } | ||||
|         // 排序逻辑 | ||||
|         if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) { | ||||
|             // TODO ProductSpuDO 已经没有maxPrice 属性 | ||||
|             //query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getMaxPrice); | ||||
|         } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) { | ||||
|             query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getSalesCount); | ||||
|         if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) { | ||||
|             query.last(String.format(" ORDER BY (sales_count + virtual_sales_count) %s, sort DESC, id DESC", | ||||
|                     pageReqVO.getSortAsc() ? "ASC" : "DESC")); | ||||
|         } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) { | ||||
|             query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getPrice) | ||||
|                     .orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId); | ||||
|         } else { | ||||
|             query.orderByDesc(ProductSpuDO::getSort).orderByDesc(ProductSpuDO::getId); | ||||
|         } | ||||
|         return selectPage(pageReqVO, query); | ||||
|     } | ||||
|   | ||||
| @@ -75,7 +75,7 @@ public interface ProductSpuService { | ||||
|     List<ProductSpuDO> getSpuList(); | ||||
|  | ||||
|     /** | ||||
|      * 获得商品 SPU 分页 | ||||
|      * 获得商品 SPU 分页,提供给挂你兰后台使用 | ||||
|      * | ||||
|      * @param pageReqVO 分页查询 | ||||
|      * @return 商品spu分页 | ||||
| @@ -83,13 +83,12 @@ public interface ProductSpuService { | ||||
|     PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获得商品 SPU 分页 | ||||
|      * 获得商品 SPU 分页,提供给用户 App 使用 | ||||
|      * | ||||
|      * @param pageReqVO 分页查询 | ||||
|      * @param status 状态 | ||||
|      * @return 商品 SPU 分页 | ||||
|      */ | ||||
|     PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status); | ||||
|     PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO); | ||||
|  | ||||
|     /** | ||||
|      * 更新商品 SPU 库存(增量) | ||||
|   | ||||
| @@ -1,14 +1,20 @@ | ||||
| package cn.iocoder.yudao.module.product.service.spu; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.util.NumberUtil; | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||
| import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; | ||||
| import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; | ||||
| import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; | ||||
| import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; | ||||
| import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; | ||||
| import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; | ||||
| import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; | ||||
| import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; | ||||
| import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||||
| import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | ||||
| import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; | ||||
| @@ -21,10 +27,7 @@ import org.springframework.transaction.annotation.Transactional; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.*; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||||
| @@ -168,8 +171,17 @@ public class ProductSpuServiceImpl implements ProductSpuService { | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status) { | ||||
|         return productSpuMapper.selectPage(pageReqVO, status); | ||||
|     public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO) { | ||||
|         // 查找时,如果查找某个分类编号,则包含它的子分类。因为顶级分类不包含商品 | ||||
|         Set<Long> categoryIds = new HashSet<>(); | ||||
|         if (pageReqVO.getCategoryId() != null && pageReqVO.getCategoryId() > 0) { | ||||
|             categoryIds.add(pageReqVO.getCategoryId()); | ||||
|             List<ProductCategoryDO> categoryChildren = categoryService.getEnableCategoryList(new ProductCategoryListReqVO() | ||||
|                     .setParentId(pageReqVO.getCategoryId()).setStatus(CommonStatusEnum.ENABLE.getStatus())); | ||||
|             categoryIds.addAll(CollectionUtils.convertList(categoryChildren, ProductCategoryDO::getId)); | ||||
|         } | ||||
|         // 分页查询 | ||||
|         return productSpuMapper.selectPage(pageReqVO, categoryIds); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV