商品模块代码提交

This commit is contained in:
Tankaikai 2025-02-24 17:32:25 +08:00
parent 6b785709f1
commit 9e6e300972
11 changed files with 203 additions and 46 deletions

View File

@ -55,7 +55,7 @@ public class ConsInfoController {
/**
* 详情
* param id 耗材信息id
* @param id 耗材信息id
*/
@GetMapping("{id}")
@OperationLog("耗材信息-详情")

View File

@ -1,5 +1,6 @@
package com.czg.controller.admin;
import com.czg.exception.CzgException;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ProdConsBindDTO;
import com.czg.product.dto.ProdSkuDTO;
@ -135,4 +136,19 @@ public class ProductController {
return CzgResult.success();
}
/**
* 商品-库存预警设置
*/
@PostMapping("stock-warning")
@OperationLog("商品-库存预警设置")
//@SaAdminCheckPermission("product:stockWarning")
public CzgResult<Void> stockWarning(@RequestParam Integer warnLine) {
AssertUtil.isNull(warnLine, "{}不能为空", "warnLine");
if (warnLine < 0) {
throw new CzgException("预警值不能小于0");
}
productService.stockWarning(warnLine);
return CzgResult.success();
}
}

View File

@ -13,6 +13,7 @@ import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* 耗材信息
@ -102,5 +103,8 @@ public class ConsInfoDTO implements Serializable {
* 结束时间 yyyy-MM-dd HH:mm:ss
*/
private String endTime;
/**
* 耗材绑定商品信息
*/
List<ProductBriefDTO> productList;
}

View File

@ -219,6 +219,14 @@ public class ProductDTO implements Serializable {
* 会员最低售价
*/
private BigDecimal lowMemberPrice;
/**
* 商品关联耗材列表
*/
private List<ProdConsRelationDTO> consList;
/**
* 耗材信息
*/
private String consName;
public Object getImages() {
return JSON.parseArray(Convert.toStr(images, "[]"));

View File

@ -34,4 +34,6 @@ public interface ProductService extends IService<Product> {
boolean markProductIsSoldOut(ProductIsSoldOutParam param);
void refundToStock(ProdRefundToStockParam param);
void stockWarning(Integer warnLine);
}

View File

@ -1,8 +1,12 @@
package com.czg.service.product.mapper;
import com.czg.product.dto.ProductBriefDTO;
import com.czg.product.entity.ProdConsRelation;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 商品耗材绑定关系
@ -13,4 +17,6 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ProdConsRelationMapper extends BaseMapper<ProdConsRelation> {
List<ProductBriefDTO> getProductListByConId(@Param("conId") Long conId);
}

View File

@ -1,9 +1,12 @@
package com.czg.service.product.mapper;
import com.czg.product.dto.ProductDTO;
import com.czg.product.entity.Product;
import com.czg.product.vo.ShopProductInfoVo;
import com.czg.product.vo.ShopProductVo;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -18,6 +21,12 @@ import java.util.List;
@Mapper
public interface ProductMapper extends BaseMapper<Product> {
Page<ProductDTO> selectProductPage();
long selectProductPage_COUNT();
List<ProductDTO> selectProductList(QueryWrapper qw);
List<ShopProductVo> selectHotsProductList(@Param("shopId") Long shopId);
List<ShopProductVo> selectGroupProductList(@Param("shopId") Long shopId);

View File

@ -8,6 +8,7 @@ import com.czg.enums.StatusEnum;
import com.czg.enums.YesNoEnum;
import com.czg.exception.CzgException;
import com.czg.product.dto.ConsInfoDTO;
import com.czg.product.dto.ProductBriefDTO;
import com.czg.product.entity.ConsGroupRelation;
import com.czg.product.entity.ConsInfo;
import com.czg.product.param.ConsSubUnitParam;
@ -15,6 +16,7 @@ import com.czg.product.service.ConsInfoService;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsGroupRelationMapper;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ProdConsRelationMapper;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
@ -38,6 +40,7 @@ import java.util.List;
public class ConsInfoServiceImpl extends ServiceImpl<ConsInfoMapper, ConsInfo> implements ConsInfoService {
private final ConsGroupRelationMapper consGroupRelationMapper;
private final ProdConsRelationMapper prodConsRelationMapper;
private QueryWrapper buildQueryWrapper(ConsInfoDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
@ -62,20 +65,33 @@ public class ConsInfoServiceImpl extends ServiceImpl<ConsInfoMapper, ConsInfo> i
@Override
public Page<ConsInfoDTO> getConsInfoPage(ConsInfoDTO param) {
QueryWrapper queryWrapper = buildQueryWrapper(param);
return super.pageAs(PageUtil.buildPage(), queryWrapper, ConsInfoDTO.class);
Page<ConsInfoDTO> page = super.pageAs(PageUtil.buildPage(), queryWrapper, ConsInfoDTO.class);
page.getRecords().parallelStream().forEach(item -> {
List<ProductBriefDTO> productList = prodConsRelationMapper.getProductListByConId(item.getId());
item.setProductList(productList);
});
return page;
}
@Override
public List<ConsInfoDTO> getConsInfoList(ConsInfoDTO param) {
QueryWrapper queryWrapper = buildQueryWrapper(param);
queryWrapper.eq(ConsInfo::getStatus, StatusEnum.ENABLED.value());
return super.listAs(queryWrapper, ConsInfoDTO.class);
List<ConsInfoDTO> list = super.listAs(queryWrapper, ConsInfoDTO.class);
list.parallelStream().forEach(item -> {
List<ProductBriefDTO> productList = prodConsRelationMapper.getProductListByConId(item.getId());
item.setProductList(productList);
});
return list;
}
@Override
public ConsInfoDTO getConsInfoById(Long id) {
Long shopId = StpKit.USER.getShopId(0L);
return super.getOneAs(query().eq(ConsInfo::getId, id).eq(ConsInfo::getShopId, shopId), ConsInfoDTO.class);
ConsInfoDTO data = super.getOneAs(query().eq(ConsInfo::getId, id).eq(ConsInfo::getShopId, shopId), ConsInfoDTO.class);
List<ProductBriefDTO> productList = prodConsRelationMapper.getProductListByConId(data.getId());
data.setProductList(productList);
return data;
}
@Override

View File

@ -10,8 +10,11 @@ import com.alibaba.fastjson2.JSONWriter;
import com.czg.enums.DeleteEnum;
import com.czg.enums.YesNoEnum;
import com.czg.exception.CzgException;
import com.czg.product.dto.ProdConsRelationDTO;
import com.czg.product.dto.ProdSkuDTO;
import com.czg.product.dto.ProductDTO;
import com.czg.product.entity.ConsInfo;
import com.czg.product.entity.ProdConsRelation;
import com.czg.product.entity.ProdSku;
import com.czg.product.entity.Product;
import com.czg.product.enums.ProductIsSaleTypeEnum;
@ -21,6 +24,8 @@ import com.czg.product.param.ProductIsSaleParam;
import com.czg.product.param.ProductIsSoldOutParam;
import com.czg.product.service.ProductService;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ProdConsRelationMapper;
import com.czg.service.product.mapper.ProdSkuMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.czg.utils.PageUtil;
@ -34,8 +39,10 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import static com.czg.product.entity.table.ProductTableDef.PRODUCT;
import static com.czg.product.entity.table.ShopProdCategoryTableDef.SHOP_PROD_CATEGORY;
@ -54,11 +61,13 @@ import static com.czg.product.entity.table.ShopProdUnitTableDef.SHOP_PROD_UNIT;
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
private final ProdSkuMapper prodSkuMapper;
private final ProdConsRelationMapper prodConsRelationMapper;
private final ConsInfoMapper consInfoMapper;
private QueryWrapper buildQueryWrapper(ProductDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
if (ObjUtil.isNotNull(param.getId())) {
queryWrapper.like(Product::getId, param.getId());
queryWrapper.eq(Product::getId, param.getId());
}
if (StrUtil.isNotEmpty(param.getName())) {
queryWrapper.like(Product::getName, param.getName());
@ -67,12 +76,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
queryWrapper.eq(Product::getCategoryId, param.getCategoryId());
}
if (ObjUtil.isNotNull(param.getSpecId())) {
queryWrapper.like(Product::getSpecId, param.getSpecId());
queryWrapper.eq(Product::getSpecId, param.getSpecId());
}
if (ObjUtil.isNotNull(param.getCreateBeginTime())) {
if (StrUtil.isNotEmpty(param.getCreateBeginTime())) {
queryWrapper.ge(Product::getCreateTime, param.getCreateBeginTime());
}
if (ObjUtil.isNotNull(param.getCreateEndTime())) {
if (StrUtil.isNotEmpty(param.getCreateEndTime())) {
queryWrapper.le(Product::getCreateTime, param.getCreateEndTime());
}
Long shopId = StpKit.USER.getShopId(0L);
@ -96,30 +105,33 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
return queryWrapper;
}
private void buildProductExtInfo(List<ProductDTO> records) {
records.parallelStream().forEach(record -> {
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().eq(ProdSku::getProductId, record.getId()).eq(ProdSku::getIsDel, DeleteEnum.NORMAL.value()), ProdSkuDTO.class);
if (CollUtil.isNotEmpty(skuList)) {
Optional<BigDecimal> lowPriceIsPresent = skuList.stream().map(obj -> NumberUtil.nullToZero(obj.getSalePrice())).min(BigDecimal::compareTo);
lowPriceIsPresent.ifPresent(record::setLowPrice);
Optional<BigDecimal> lowMemberPriceIsPresent = skuList.stream().map(obj -> NumberUtil.nullToZero(obj.getMemberPrice())).min(BigDecimal::compareTo);
lowMemberPriceIsPresent.ifPresent(record::setLowMemberPrice);
}
record.setSkuList(skuList);
List<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByQueryAs(query().eq(ProdConsRelation::getProductId, record.getId()), ProdConsRelationDTO.class);
record.setConsList(consList);
if (CollUtil.isNotEmpty(consList)) {
List<Long> consIds = consList.stream().map(ProdConsRelationDTO::getConsInfoId).distinct().toList();
String consName = consInfoMapper.selectOneByQueryAs(query().select("GROUP_CONCAT(con_name SEPARATOR '、')").eq(ConsInfo::getId, consIds), String.class);
record.setConsName(consName);
}
});
}
@Override
public Page<ProductDTO> getProductPage(ProductDTO param) {
QueryWrapper queryWrapper = buildFullQueryWrapper(param);
Page<ProductDTO> page = super.pageAs(PageUtil.buildPage(), queryWrapper, ProductDTO.class);
List<ProductDTO> records = page.getRecords();
List<Long> prodIdList = records.stream().map(ProductDTO::getId).distinct().toList();
if (CollUtil.isEmpty(prodIdList)) {
return page;
}
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().in(ProdSku::getProductId, prodIdList).eq(ProdSku::getIsDel, DeleteEnum.NORMAL.value()), ProdSkuDTO.class);
Map<Long, List<ProdSkuDTO>> collect = skuList.stream().collect(Collectors.groupingBy(ProdSkuDTO::getProductId));
for (ProductDTO record : records) {
List<ProdSkuDTO> list = collect.getOrDefault(record.getId(), Collections.emptyList());
if (CollUtil.isEmpty(list)) {
continue;
}
Optional<BigDecimal> lowPriceIsPresent = list.stream().map(obj -> NumberUtil.nullToZero(obj.getSalePrice())).min(BigDecimal::compareTo);
lowPriceIsPresent.ifPresent(record::setLowPrice);
Optional<BigDecimal> lowMemberPriceIsPresent = list.stream().map(obj -> NumberUtil.nullToZero(obj.getMemberPrice())).min(BigDecimal::compareTo);
lowMemberPriceIsPresent.ifPresent(record::setLowMemberPrice);
record.setSkuList(list);
}
buildProductExtInfo(records);
return page;
}
@ -127,22 +139,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
public List<ProductDTO> getProductList(ProductDTO param) {
QueryWrapper queryWrapper = buildFullQueryWrapper(param);
List<ProductDTO> records = super.listAs(queryWrapper, ProductDTO.class);
if (CollUtil.isEmpty(records)) {
return records;
}
List<Long> prodIdList = records.stream().map(ProductDTO::getId).distinct().toList();
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().in(ProdSku::getProductId, prodIdList).eq(ProdSku::getIsDel, DeleteEnum.NORMAL.value()), ProdSkuDTO.class);
Map<Long, List<ProdSkuDTO>> collect = skuList.stream().collect(Collectors.groupingBy(ProdSkuDTO::getProductId));
for (ProductDTO record : records) {
List<ProdSkuDTO> list = collect.getOrDefault(record.getId(), Collections.emptyList());
Optional<BigDecimal> lowPriceIsPresent = list.stream().map(ProdSkuDTO::getSalePrice).min(BigDecimal::compareTo);
lowPriceIsPresent.ifPresent(record::setLowPrice);
Optional<BigDecimal> lowMemberPriceIsPresent = list.stream().map(ProdSkuDTO::getMemberPrice).min(BigDecimal::compareTo);
lowMemberPriceIsPresent.ifPresent(record::setLowMemberPrice);
record.setSkuList(list);
}
buildProductExtInfo(records);
return records;
}
@ -154,6 +151,8 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
ProductDTO dto = super.getOneAs(queryWrapper, ProductDTO.class);
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().eq(ProdSku::getProductId, id).eq(ProdSku::getIsDel, DeleteEnum.NORMAL.value()), ProdSkuDTO.class);
dto.setSkuList(skuList);
List<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByQueryAs(query().eq(ProdConsRelation::getProductId, dto.getId()), ProdConsRelationDTO.class);
dto.setConsList(consList);
return dto;
}
@ -315,4 +314,13 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
entity.setIsRefundStock(param.getIsReturn());
super.updateById(entity);
}
@Override
public void stockWarning(Integer warnLine) {
Long shopId = StpKit.USER.getShopId(0L);
UpdateChain.of(Product.class)
.set(Product::getWarnLine, warnLine)
.eq(Product::getShopId, shopId)
.update();
}
}

View File

@ -3,4 +3,12 @@
<mapper namespace="com.czg.service.product.mapper.ProdConsRelationMapper">
<select id="getProductListByConId" resultType="com.czg.product.dto.ProductBriefDTO">
select t2.id,
t2.name,
t2.cover_img
from tb_prod_cons_relation t1
inner join tb_product t2 on t1.product_id = t2.id
where t1.cons_info_id = #{conId}
</select>
</mapper>

View File

@ -2,6 +2,73 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.product.mapper.ProductMapper">
<sql id="productQuery">
SELECT t1.id,
t1.days,
t1.name,
t1.sort,
t1.type,
t1.is_del,
t1.is_hot,
t1.images,
t1.is_sale,
t1.shop_id,
t1.spec_id,
t1.unit_id,
t1.weight,
t1.end_time,
t1.is_stock,
t1.pack_fee,
t1.cover_img,
t1.warn_line,
t1.group_snap,
t1.group_type,
t1.start_time,
t1.category_id,
t1.create_time,
t1.short_title,
t1.update_time,
t1.is_sold_stock,
t1.stock_number,
t1.is_refund_stock,
t1.select_spec_info,
t1.group_category_id,
t1.is_allow_temp_modify_price,
t2.name AS unit_name,
t3.name AS category_name,
t4.name AS spec_name,
t4.full_name AS spec_full_name
FROM tb_product t1
LEFT JOIN tb_shop_prod_unit t2 ON t2.id = t1.unit_id
LEFT JOIN tb_shop_prod_category t3 ON t3.id = t1.category_id
LEFT JOIN tb_shop_prod_spec t4 ON t4.id = t1.spec_id
</sql>
<sql id="productQueryWhere">
<where>
and t1.shop_id = #{shopId}
and t1.is_del = 0
<if test="id != null">
and t1.id = #{id}
</if>
<if test="name != null and name != ''">
and t1.name like concat('%', #{name}, '%')
</if>
<if test="categoryId != null">
and t1.category_id = #{categoryId}
</if>
<if test="specId != null">
and t1.spec_id = #{specId}
</if>
<if test="createBeginTime != null and createBeginTime != ''">
and t1.name >= #{createBeginTime}
</if>
<if test="createEndTime != null and createEndTime != ''">
<![CDATA[
and t1.name <= #{createEndTime}
]]>
</if>
</where>
</sql>
<sql id="shopProductQuery">
select t1.id,
t1.name,
@ -37,6 +104,19 @@
group by x.product_id) t2 on t1.id = t2.product_id
left join tb_shop_prod_unit t3 on t1.unit_id = t3.id
</sql>
<select id="selectProductPage" resultType="com.czg.product.dto.ProductDTO">
<include refid="productQuery"/>
${qwSql}
limit ${pageOffset}, ${pageSize}
</select>
<select id="selectProductPage_COUNT" resultType="long">
select count(*)
from tb_product t1 ${qwSql}
</select>
<select id="selectProductList" resultType="com.czg.product.dto.ProductDTO">
<include refid="productQuery"/>
${qwSql}
</select>
<select id="selectHotsProductList" resultType="com.czg.product.vo.ShopProductVo">
<include refid="shopProductQuery"/>