完善 App 商品搜索的逻辑

This commit is contained in:
YunaiV 2023-04-26 20:13:12 +08:00
parent a5f018104e
commit 3ced6a3240
8 changed files with 87 additions and 32 deletions

View File

@ -1,8 +1,18 @@
### 获得订单交易的分页 TODO ### 获得订单交易的分页(默认)
GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10 GET {{appApi}}/product/spu/page?pageNo=1&pageSize=10
Authorization: Bearer {{appToken}} Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}} 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 明细 ### 获得商品 SPU 明细
GET {{appApi}}/product/spu/get-detail?id=4 GET {{appApi}}/product/spu/get-detail?id=4
tenant-id: {{appTenentId}} tenant-id: {{appTenentId}}

View File

@ -49,8 +49,8 @@ public class AppProductSpuController {
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得商品 SPU 分页") @Operation(summary = "获得商品 SPU 分页")
public CommonResult<PageResult<AppProductSpuPageItemRespVO>> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) { public CommonResult<PageResult<AppProductSpuPageItemRespVO>> getSpuPage(@Valid AppProductSpuPageReqVO pageVO) {
PageResult<ProductSpuDO> pageResult = productSpuService.getSpuPage(pageVO, ProductSpuStatusEnum.ENABLE.getStatus()); PageResult<ProductSpuDO> pageResult = productSpuService.getSpuPage(pageVO);
return success(ProductSpuConvert.INSTANCE.convertPage02(pageResult)); return success(ProductSpuConvert.INSTANCE.convertPageForGetSpuPage(pageResult));
} }
@GetMapping("/get-detail") @GetMapping("/get-detail")

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.product.controller.app.spu.vo; 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 io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -15,21 +16,24 @@ public class AppProductSpuPageItemRespVO {
private Long id; private Long id;
@Schema(description = "商品名称", required = true, example = "芋道") @Schema(description = "商品名称", required = true, example = "芋道")
@NotEmpty(message = "商品名称不能为空")
private String name; private String name;
@Schema(description = "分类编号", required = true) @Schema(description = "分类编号", required = true)
@NotNull(message = "分类编号不能为空")
private Long categoryId; private Long categoryId;
@Schema(description = "商品片的数组", required = true) @Schema(description = "商品封面", required = true)
private List<String> picUrls; private String picUrl;
@Schema(description = " 最小价格,单位使用:分", required = true, example = "1024") @Schema(description = "商品轮播图", required = true)
private Integer minPrice; private List<String> sliderPicUrls;
@Schema(description = "最大价格,单位使用:分", required = true, example = "1024") @Schema(description = "商品价格,单位使用:分", required = true, example = "1024")
private Integer maxPrice; private Integer price;
// ========== SKU 相关字段 =========
@Schema(description = "库存", required = true, example = "666")
private Integer stock;
// ========== 统计相关字段 ========= // ========== 统计相关字段 =========

View File

@ -19,18 +19,23 @@ public class AppProductSpuPageReqVO extends PageParam {
public static final String SORT_FIELD_PRICE = "price"; public static final String SORT_FIELD_PRICE = "price";
public static final String SORT_FIELD_SALES_COUNT = "salesCount"; public static final String SORT_FIELD_SALES_COUNT = "salesCount";
public static final String RECOMMEND_TYPE_HOT = "hot";
@Schema(description = "分类编号", example = "1") @Schema(description = "分类编号", example = "1")
private Long categoryId; private Long categoryId;
@Schema(description = "关键字", example = "好看") @Schema(description = "关键字", example = "好看")
private String keyword; private String keyword;
@Schema(description = "排序字段", example = "price") // 参见 AppSpuPageReqVO.SORT_FIELD_XXX 常量 @Schema(description = "排序字段", example = "price") // 参见 AppProductSpuPageReqVO.SORT_FIELD_XXX 常量
private String sortField; private String sortField;
@Schema(description = "排序方式", example = "true") @Schema(description = "排序方式", example = "true")
private Boolean sortAsc; private Boolean sortAsc;
@Schema(description = "推荐类型", example = "hot") // 参见 AppProductSpuPageReqVO.RECOMMEND_TYPE_XXX 常亮
private String recommendType;
@AssertTrue(message = "排序字段不合法") @AssertTrue(message = "排序字段不合法")
@JsonIgnore @JsonIgnore
public boolean isSortFieldValid() { public boolean isSortFieldValid() {

View File

@ -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.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO; import cn.iocoder.yudao.module.product.service.property.bo.ProductPropertyValueDetailRespBO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.ArrayList; import java.util.ArrayList;
@ -75,8 +76,6 @@ public interface ProductSpuConvert {
List<AppProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> skus); List<AppProductSpuDetailRespVO.Sku> convertList03(List<ProductSkuDO> skus);
AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue); AppProductPropertyValueDetailRespVO convert03(ProductPropertyValueDetailRespBO propertyValue);
PageResult<AppProductSpuPageItemRespVO> convertPage02(PageResult<ProductSpuDO> page);
default ProductSpuDetailRespVO convert03(ProductSpuDO spu, List<ProductSkuDO> skus, default ProductSpuDetailRespVO convert03(ProductSpuDO spu, List<ProductSkuDO> skus,
List<ProductPropertyValueDetailRespBO> propertyValues) { List<ProductPropertyValueDetailRespBO> propertyValues) {
ProductSpuDetailRespVO spuVO = convert03(spu); ProductSpuDetailRespVO spuVO = convert03(spu);
@ -105,4 +104,14 @@ public interface ProductSpuConvert {
List<ProductSpuDetailRespVO.Sku> convertList04(List<ProductSkuDO> skus); List<ProductSpuDetailRespVO.Sku> convertList04(List<ProductSkuDO> skus);
ProductPropertyValueDetailRespVO convert04(ProductPropertyValueDetailRespBO propertyValue); 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);
} }

View File

@ -1,11 +1,15 @@
package cn.iocoder.yudao.module.product.dal.mysql.spu; 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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 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.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.admin.spu.vo.ProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; 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.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@ -46,16 +50,28 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
.orderByDesc(ProductSpuDO::getSort)); .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>() LambdaQueryWrapperX<ProductSpuDO> query = new LambdaQueryWrapperX<ProductSpuDO>()
.eqIfPresent(ProductSpuDO::getCategoryId, pageReqVO.getCategoryId()) .likeIfPresent(ProductSpuDO::getName, pageReqVO.getKeyword()) // 关键字匹配目前只匹配商品名
.eqIfPresent(ProductSpuDO::getStatus, status); .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)) { if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) {
// TODO ProductSpuDO 已经没有maxPrice 属性 query.last(String.format(" ORDER BY (sales_count + virtual_sales_count) %s, sort DESC, id DESC",
//query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getMaxPrice); pageReqVO.getSortAsc() ? "ASC" : "DESC"));
} else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_SALES_COUNT)) { } else if (Objects.equals(pageReqVO.getSortField(), AppProductSpuPageReqVO.SORT_FIELD_PRICE)) {
query.orderBy(true, pageReqVO.getSortAsc(), ProductSpuDO::getSalesCount); 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); return selectPage(pageReqVO, query);
} }

View File

@ -75,7 +75,7 @@ public interface ProductSpuService {
List<ProductSpuDO> getSpuList(); List<ProductSpuDO> getSpuList();
/** /**
* 获得商品 SPU 分页 * 获得商品 SPU 分页提供给挂你兰后台使用
* *
* @param pageReqVO 分页查询 * @param pageReqVO 分页查询
* @return 商品spu分页 * @return 商品spu分页
@ -83,13 +83,12 @@ public interface ProductSpuService {
PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO); PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO);
/** /**
* 获得商品 SPU 分页 * 获得商品 SPU 分页提供给用户 App 使用
* *
* @param pageReqVO 分页查询 * @param pageReqVO 分页查询
* @param status 状态
* @return 商品 SPU 分页 * @return 商品 SPU 分页
*/ */
PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status); PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO);
/** /**
* 更新商品 SPU 库存增量 * 更新商品 SPU 库存增量

View File

@ -1,14 +1,20 @@
package cn.iocoder.yudao.module.product.service.spu; package cn.iocoder.yudao.module.product.service.spu;
import cn.hutool.core.collection.CollUtil; 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.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.sku.vo.ProductSkuCreateOrUpdateReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; 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.ProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; 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.controller.app.spu.vo.AppProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; 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.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; 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 org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
@ -168,8 +171,17 @@ public class ProductSpuServiceImpl implements ProductSpuService {
} }
@Override @Override
public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO, Integer status) { public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO) {
return productSpuMapper.selectPage(pageReqVO, status); // 查找时如果查找某个分类编号则包含它的子分类因为顶级分类不包含商品
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 @Override