商品模块代码提交

This commit is contained in:
Tankaikai
2025-02-18 10:57:58 +08:00
parent 50f19eafbf
commit 81b326853c
9 changed files with 374 additions and 7 deletions

View File

@@ -0,0 +1,37 @@
package com.czg.controller.user;
import com.czg.log.annotation.OperationLog;
import com.czg.product.param.MiniHomeProductParam;
import com.czg.product.service.UProductService;
import com.czg.product.vo.MiniAppHomeProductVo;
import com.czg.resp.CzgResult;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户端商品相关接口
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-16
*/
@AllArgsConstructor
@RestController
@RequestMapping("/user/product")
public class UProductController {
private final UProductService uProductService;
/**
* 小程序点餐-首页-商品列表
*/
@GetMapping("/miniApp/home/queryProduct")
@OperationLog("小程序点餐-首页-商品列表")
public CzgResult<MiniAppHomeProductVo> queryProductForMiniAppHome(MiniHomeProductParam param) {
MiniAppHomeProductVo data = uProductService.queryProductForMiniAppHome(param);
return CzgResult.success(data);
}
}

View File

@@ -16,7 +16,6 @@ import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
/**
* 商品分组
@@ -100,9 +99,4 @@ public class ProdGroupDTO implements Serializable {
* 商品简要信息列表
*/
private List<ProductBriefDTO> productList;
/**
* 分组商品信息,用于小程序首页展示
*/
private List<Map<String,Object>> products;
}

View File

@@ -84,7 +84,7 @@ public class ProductDTO implements Serializable {
@NotBlank(message = "商品类型不能为空", groups = DefaultGroup.class)
private String type;
/**
* 0 固定套餐 1可选套餐
* 套餐类型 0 固定套餐 1可选套餐
*/
private Integer groupType;
/**

View File

@@ -0,0 +1,31 @@
package com.czg.product.param;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 小程序首页商品请求参数
* @author tankaikai
* @since 2025-02-17 15:02
*/
@Data
public class MiniHomeProductParam implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 商品分组ID
*/
private Long prodGroupId;
/**
* 商品分组ID
*/
@JSONField(serialize = false)
private List<Long> productIdList;
}

View File

@@ -0,0 +1,16 @@
package com.czg.product.service;
import com.czg.product.entity.Product;
import com.czg.product.param.MiniHomeProductParam;
import com.czg.product.vo.MiniAppHomeProductVo;
import com.mybatisflex.core.service.IService;
/**
* 用户端商品Service
* @author tankaikai
* @since 2025-02-17 14:57
*/
public interface UProductService extends IService<Product> {
MiniAppHomeProductVo queryProductForMiniAppHome(MiniHomeProductParam param);
}

View File

@@ -0,0 +1,22 @@
package com.czg.product.vo;
import com.czg.product.entity.ProdGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 分组商品信息,用于小程序首页展示
* @author tankaikai
* @since 2025-02-18 09:34
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class MiniAppHomeProdGroupVo extends ProdGroup {
/**
* 分组商品信息,用于小程序首页展示
*/
private List<MiniAppHomeProductInfoVo> products;
}

View File

@@ -0,0 +1,70 @@
package com.czg.product.vo;
import com.czg.product.dto.ProdSkuDTO;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
/**
* 小程序首页商品信息VO
* @author tankaikai
* @since 2025-02-17 14:41
*/
@Data
public class MiniAppHomeProductInfoVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 商品id
*/
private Long id;
/**
* 商品名称
*/
private String name;
/**
* 商品封面图
*/
private String coverImg;
/**
* 商品图片集url
*/
private Object images;
/**
* 单位名称
*/
private String unitName;
/**
* 分类名称
*/
private String categoryName;
/**
* 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
*/
private String type;
/**
* 套餐类型 0 固定套餐 1可选套餐
*/
private Integer groupType;
/**
* 商品可选规格 {"口味":[{"甜度":["少甜","中甜","多甜"]},{"辣度":["微辣","重辣","变态辣"]},{"小料":["葱花","香菜","折耳根"]}]}
*/
private Object selectSpecInfo;
/**
* 最低售价
*/
private BigDecimal lowPrice;
/**
* 会员最低售价
*/
private BigDecimal lowMemberPrice;
/**
* 商品SKU列表
*/
private List<ProdSkuDTO> skuList;
}

View File

@@ -0,0 +1,31 @@
package com.czg.product.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 小程序首页商品展示VO
* @author tankaikai
* @since 2025-02-17 14:41
*/
@Data
public class MiniAppHomeProductVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 热销商品
*/
List<MiniAppHomeProductInfoVo> hots;
/**
* 分组商品信息
*/
List<MiniAppHomeProdGroupVo> productInfo;
}

View File

@@ -0,0 +1,166 @@
package com.czg.service.product.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.czg.enums.DeleteEnum;
import com.czg.enums.StatusEnum;
import com.czg.enums.YesNoEnum;
import com.czg.product.dto.ProdSkuDTO;
import com.czg.product.dto.ProductDTO;
import com.czg.product.entity.ProdGroup;
import com.czg.product.entity.ProdGroupRelation;
import com.czg.product.entity.ProdSku;
import com.czg.product.entity.Product;
import com.czg.product.param.MiniHomeProductParam;
import com.czg.product.service.UProductService;
import com.czg.product.vo.MiniAppHomeProdGroupVo;
import com.czg.product.vo.MiniAppHomeProductInfoVo;
import com.czg.product.vo.MiniAppHomeProductVo;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ProdGroupMapper;
import com.czg.service.product.mapper.ProdGroupRelationMapper;
import com.czg.service.product.mapper.ProdSkuMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.TextStyle;
import java.util.*;
import java.util.stream.Collectors;
import static com.czg.product.entity.table.ProductTableDef.PRODUCT;
import static com.czg.product.entity.table.ShopProdCategoryTableDef.SHOP_PROD_CATEGORY;
import static com.czg.product.entity.table.ShopProdSpecTableDef.SHOP_PROD_SPEC;
import static com.czg.product.entity.table.ShopProdUnitTableDef.SHOP_PROD_UNIT;
/**
* 商品
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-16
*/
@Slf4j
@AllArgsConstructor
@Service
public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements UProductService {
private final ProductMapper productMapper;
private final ProdSkuMapper prodSkuMapper;
private final ProdGroupMapper prodGroupMapper;
private final ProdGroupRelationMapper prodGroupRelationMapper;
private QueryWrapper buildQueryWrapper(MiniHomeProductParam param) {
Long shopId = StpKit.USER.getShopId(0L);
String weekDayEnName = getWeekDayEnName();
LocalTime now = LocalTime.now().withNano(0);
QueryWrapper queryWrapper = query();
queryWrapper.select(PRODUCT.ALL_COLUMNS)
.select(SHOP_PROD_UNIT.NAME.as(ProductDTO::getUnitName))
.select(SHOP_PROD_CATEGORY.NAME.as(ProductDTO::getCategoryName))
.select(SHOP_PROD_SPEC.NAME.as(ProductDTO::getSpecName), SHOP_PROD_SPEC.FULL_NAME.as(ProductDTO::getSpecFullName))
.from(PRODUCT)
.leftJoin(SHOP_PROD_UNIT).on(SHOP_PROD_UNIT.ID.eq(PRODUCT.UNIT_ID))
.leftJoin(SHOP_PROD_CATEGORY).on(SHOP_PROD_CATEGORY.ID.eq(PRODUCT.CATEGORY_ID))
.leftJoin(SHOP_PROD_SPEC).on(SHOP_PROD_SPEC.ID.eq(PRODUCT.SPEC_ID))
.where(PRODUCT.SHOP_ID.eq(shopId))
.and(PRODUCT.DAYS.like(weekDayEnName))
.and(PRODUCT.START_TIME.le(now))
.and(PRODUCT.END_TIME.ge(now))
.and(PRODUCT.IS_DEL.eq(DeleteEnum.NORMAL.value()))
.and(PRODUCT.IS_SALE.eq(YesNoEnum.YES.value()))
.orderBy(PRODUCT.SORT, false)
.orderBy(PRODUCT.ID, false);
if (CollUtil.isNotEmpty(param.getProductIdList())) {
queryWrapper.and(PRODUCT.ID.in(param.getProductIdList()));
}
return queryWrapper;
}
private QueryWrapper buildHotsQueryWrapper(MiniHomeProductParam param) {
// 查询在可售时间内的热门商品
QueryWrapper queryWrapper = buildQueryWrapper(param);
queryWrapper.and(PRODUCT.IS_HOT.eq(YesNoEnum.YES.value()));
return queryWrapper;
}
private List<MiniAppHomeProductInfoVo> buildProductList(QueryWrapper queryWrapper) {
List<ProductDTO> dtoList = productMapper.selectListByQueryAs(queryWrapper, ProductDTO.class);
List<Long> prodIdList = dtoList.stream().map(ProductDTO::getId).distinct().toList();
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().in(ProdSku::getProductId, prodIdList), ProdSkuDTO.class);
Map<Long, List<ProdSkuDTO>> collect = skuList.stream().collect(Collectors.groupingBy(ProdSkuDTO::getProductId));
List<MiniAppHomeProductInfoVo> products = new ArrayList<>();
for (ProductDTO dto : dtoList) {
MiniAppHomeProductInfoVo prod = new MiniAppHomeProductInfoVo();
prod.setId(dto.getId());
prod.setName(dto.getName());
prod.setCoverImg(dto.getCoverImg());
prod.setImages(dto.getImages());
prod.setUnitName(dto.getUnitName());
prod.setCategoryName(dto.getCategoryName());
prod.setType(dto.getType());
prod.setGroupType(dto.getGroupType());
prod.setSelectSpecInfo(dto.getSelectSpecInfo());
List<ProdSkuDTO> list = collect.getOrDefault(dto.getId(), Collections.emptyList());
Optional<BigDecimal> lowPriceIsPresent = list.stream().map(ProdSkuDTO::getSalePrice).min(BigDecimal::compareTo);
lowPriceIsPresent.ifPresent(prod::setLowPrice);
Optional<BigDecimal> lowMemberPriceIsPresent = list.stream().map(ProdSkuDTO::getMemberPrice).min(BigDecimal::compareTo);
lowMemberPriceIsPresent.ifPresent(prod::setLowMemberPrice);
prod.setSkuList(list);
products.add(prod);
}
return products;
}
@Override
public MiniAppHomeProductVo queryProductForMiniAppHome(MiniHomeProductParam param) {
Long shopId = StpKit.USER.getShopId(0L);
MiniAppHomeProductVo vo = new MiniAppHomeProductVo();
List<MiniAppHomeProductInfoVo> hots = buildProductList(buildHotsQueryWrapper(param));
vo.setHots(hots);
// 查询可用商品分组,构建分组商品数据
QueryWrapper queryWrapper = query()
.eq(ProdGroup::getShopId, shopId)
.eq(ProdGroup::getStatus, StatusEnum.ENABLED.value())
.orderBy(ProdGroup::getSort, true);
if (param.getProdGroupId() != null) {
queryWrapper.eq(ProdGroup::getId, param.getProdGroupId());
}
List<MiniAppHomeProdGroupVo> groupList = prodGroupMapper.selectListByQueryAs(queryWrapper, MiniAppHomeProdGroupVo.class);
for (MiniAppHomeProdGroupVo dto : groupList) {
List<Long> productIdList = prodGroupRelationMapper.selectObjectListByQueryAs(query().select(ProdGroupRelation::getProductId).eq(ProdGroupRelation::getProdGroupId, dto.getId()).orderBy(ProdGroupRelation::getSort, true), Long.class);
if (CollUtil.isNotEmpty(productIdList)) {
param.setProductIdList(productIdList);
List<MiniAppHomeProductInfoVo> products = buildProductList(buildQueryWrapper(param));
dto.setProducts(products);
} else {
dto.setProducts(new ArrayList<>());
}
}
vo.setProductInfo(groupList);
return vo;
}
/**
* 获取当前日期是星期几的英文名称
*
* @return 星期几的英文名称,例如 "Monday" 或 "Friday"
*/
private String getWeekDayEnName() {
// 获取当前日期
LocalDate currentDate = LocalDate.now();
// 获取当前日期是星期几,返回一个 DayOfWeek 枚举类型的实例
DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
return dayOfWeek.getDisplayName(TextStyle.FULL, Locale.ENGLISH);
}
}