From 7bf20ec72e5ffe71b5a83cbbd0cfcf2555029e6b Mon Sep 17 00:00:00 2001 From: "ex_yang.li@ca-nio.com" Date: Mon, 5 Sep 2022 20:44:04 +0800 Subject: [PATCH 01/78] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/optional/mall/order.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/optional/mall/order.sql b/sql/optional/mall/order.sql index 21e60200d..aeb738d03 100644 --- a/sql/optional/mall/order.sql +++ b/sql/optional/mall/order.sql @@ -73,4 +73,4 @@ CREATE TABLE `trade_order_item` `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB COMMENT ='交易订单明细表'; \ No newline at end of file +) ENGINE = InnoDB COMMENT ='交易订单明细表'; From 15798cea108390075f788ec491ecc3a1f5988d76 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 12 Sep 2022 21:37:24 +0800 Subject: [PATCH 02/78] =?UTF-8?q?mall=EF=BC=9A=E4=BB=B7=E6=A0=BC=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E7=9A=84=20API=20=E7=AE=80=E5=8D=95=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/price/dto/PriceCalculateRespDTO.java | 75 ++++--- .../yudao-module-market-biz/pom.xml | 5 + .../market/api/discount/package-info.java | 1 + .../{service => api}/price/PriceApiImpl.java | 16 +- .../market/convert/price/PriceConvert.java | 40 ++++ .../market/service/price/PriceService.java | 21 ++ .../service/price/PriceServiceImpl.java | 64 ++++++ .../module/product/api/sku/ProductSkuApi.java | 20 +- ...nfoRespDTO.java => ProductSkuRespDTO.java} | 4 +- .../module/product/api/spu/ProductSpuApi.java | 13 +- .../product/api/spu/dto/SpuInfoRespDTO.java | 10 +- .../product/enums/ErrorCodeConstants.java | 1 + .../product/api/sku/ProductSkuApiImpl.java | 25 ++- .../product/api/spu/ProductSpuApiImpl.java | 7 +- .../admin/sku/vo/ProductSkuBaseVO.java | 2 +- .../convert/sku/ProductSkuConvert.java | 7 +- .../enums/{enums => }/ErrorCodeConstants.java | 14 +- .../controller/app/base/package-info.java | 4 + .../AppProductPropertyValueDetailRespVO.java | 23 ++ .../app/base/sku/AppProductSkuBaseRespVO.java | 34 +++ .../app/base/spu/AppProductSpuBaseRespVO.java | 25 +++ .../controller/app/cart/CartController.java | 71 ------ .../app/cart/TradeCartController.http | 47 ++++ .../app/cart/TradeCartController.java | 84 +++++++ .../app/cart/vo/AppTradeCartDetailRespVO.java | 118 ++++++++++ .../vo/AppTradeCartItemAddCountReqVO.java | 23 ++ .../vo/AppTradeCartItemUpdateCountReqVO.java | 23 ++ .../AppTradeCartItemUpdateSelectedReqVO.java | 22 ++ .../controller/app/cart/vo/CartDetailVO.java | 211 ------------------ .../app/order/AppTradeOrderController.java | 4 +- .../trade/convert/cart/TradeCartConvert.java | 45 ++++ .../convert/order/TradeOrderItemConvert.java | 2 +- .../trade/convert/sku/ProductSkuConvert.java | 1 + .../{CartItemDO.java => TradeCartItemDO.java} | 12 +- .../dal/mysql/cart/TradeCartItemMapper.java | 47 ++++ .../trade/service/cart/TradeCartService.java | 66 ++++++ .../service/cart/TradeCartServiceImpl.java | 184 +++++++++++++++ .../service/order/TradeOrderServiceImpl.java | 20 +- .../src/main/resources/application-local.yaml | 1 + 39 files changed, 1017 insertions(+), 375 deletions(-) create mode 100644 yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/discount/package-info.java rename yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/{service => api}/price/PriceApiImpl.java (58%) create mode 100644 yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/price/PriceConvert.java create mode 100644 yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceService.java create mode 100644 yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceServiceImpl.java rename yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/{SkuInfoRespDTO.java => ProductSkuRespDTO.java} (95%) rename yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/{enums => }/ErrorCodeConstants.java (61%) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/CartController.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/CartDetailVO.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/{CartItemDO.java => TradeCartItemDO.java} (91%) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java diff --git a/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/price/dto/PriceCalculateRespDTO.java b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/price/dto/PriceCalculateRespDTO.java index dc4f10a10..3fc247a02 100644 --- a/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/price/dto/PriceCalculateRespDTO.java +++ b/yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/price/dto/PriceCalculateRespDTO.java @@ -19,15 +19,10 @@ public class PriceCalculateRespDTO { */ private Order order; - /** - * 商品 SKU 数组 - */ - private List items; - /** * 营销活动数组 * - * 只对应 {@link #items} 商品匹配的活动 + * 只对应 {@link Order#items} 商品匹配的活动 */ private List promotions; @@ -40,13 +35,13 @@ public class PriceCalculateRespDTO { /** * 商品原价(总),单位:分 * - * 基于 {@link Item#getTotalOriginalPrice()} 求和 + * 基于 {@link OrderItem#getTotalOriginalPrice()} 求和 */ private Integer skuOriginalPrice; /** * 商品优惠(总),单位:分 * - * 基于 {@link Item#getTotalPromotionPrice()} 求和 + * 基于 {@link OrderItem#getTotalPromotionPrice()} 求和 */ private Integer skuPromotionPrice; /** @@ -69,6 +64,10 @@ public class PriceCalculateRespDTO { */ // * - {@link #couponPrice} // TODO 芋艿:靠营销表记录 private Integer payPrice; + /** + * 商品 SKU 数组 + */ + private List items; // ========== 营销基本信息 ========== /** @@ -85,10 +84,15 @@ public class PriceCalculateRespDTO { } /** - * 商品 SKU + * 订单商品 SKU */ @Data - public static class Item extends PriceCalculateReqDTO.Item { + public static class OrderItem extends PriceCalculateReqDTO.Item { + + /** + * 购买数量 + */ + private Integer count; /** * 商品原价(单),单位:分 @@ -140,6 +144,10 @@ public class PriceCalculateRespDTO { * 例如说:营销活动的编号、优惠劵的编号 */ private Long id; + /** + * 营销名字 + */ + private String name; /** * 营销类型 * @@ -152,10 +160,6 @@ public class PriceCalculateRespDTO { * 枚举 {@link PromotionLevelEnum} */ private Integer level; - /** - * 匹配的商品 SKU 数组 - */ - private List items; /** * 计算时的原价(总),单位:分 */ @@ -164,6 +168,13 @@ public class PriceCalculateRespDTO { * 计算时的优惠(总),单位:分 */ private Integer totalPromotionPrice; + /** + * 匹配的商品 SKU 数组 + */ + private List items; + + // ========== 匹配情况 ========== + /** * 是否满足优惠条件 */ @@ -176,26 +187,26 @@ public class PriceCalculateRespDTO { */ private String meetTip; + } + + /** + * 营销匹配的商品 SKU + */ + @Data + public static class PromotionItem { + /** - * 匹配的商品 SKU + * 商品 SKU 编号 */ - @Data - public static class Item { - - /** - * 商品 SKU 编号 - */ - private Long skuId; - /** - * 计算时的原价(总),单位:分 - */ - private Integer totalOriginalPrice; - /** - * 计算时的优惠(总),单位:分 - */ - private Integer totalPromotionPrice; - - } + private Long skuId; + /** + * 计算时的原价(总),单位:分 + */ + private Integer totalOriginalPrice; + /** + * 计算时的优惠(总),单位:分 + */ + private Integer totalPromotionPrice; } diff --git a/yudao-module-mall/yudao-module-market-biz/pom.xml b/yudao-module-mall/yudao-module-market-biz/pom.xml index e7fa33e9d..669e9ed63 100644 --- a/yudao-module-mall/yudao-module-market-biz/pom.xml +++ b/yudao-module-mall/yudao-module-market-biz/pom.xml @@ -24,6 +24,11 @@ yudao-module-market-api ${revision} + + cn.iocoder.boot + yudao-module-product-api + ${revision} + diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/discount/package-info.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/discount/package-info.java new file mode 100644 index 000000000..47820ec86 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/discount/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.market.api.discount; diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceApiImpl.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/price/PriceApiImpl.java similarity index 58% rename from yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceApiImpl.java rename to yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/price/PriceApiImpl.java index 6b8663d1e..74806dc0a 100644 --- a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceApiImpl.java +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/price/PriceApiImpl.java @@ -1,24 +1,26 @@ -package cn.iocoder.yudao.module.market.service.price; +package cn.iocoder.yudao.module.market.api.price; -import cn.iocoder.yudao.module.market.api.price.PriceApi; import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; +import cn.iocoder.yudao.module.market.service.price.PriceService; import org.springframework.stereotype.Service; +import javax.annotation.Resource; + /** * 价格 API 实现类 * - * TODO 完善注释 - * - * @author TODO + * @author 芋道源码 */ @Service public class PriceApiImpl implements PriceApi { + @Resource + private PriceService priceService; + @Override public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) { - // TODO fixme:实现逻辑 - return new PriceCalculateRespDTO(); + return priceService.calculatePrice(calculateReqDTO); } } diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/price/PriceConvert.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/price/PriceConvert.java new file mode 100644 index 000000000..c88c2a2c4 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/price/PriceConvert.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.market.convert.price; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Mapper +public interface PriceConvert { + + PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class); + + default PriceCalculateRespDTO convert(PriceCalculateReqDTO calculateReqDTO, List skuList) { + // 创建 PriceCalculateRespDTO 对象 + PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO(); + priceCalculate.setOrder(new PriceCalculateRespDTO.Order().setSkuOriginalPrice(0).setSkuPromotionPrice(0) + .setOrderPromotionPrice(0).setDeliveryPrice(0).setPayPrice(0).setItems(new ArrayList<>()) + .setCouponId(calculateReqDTO.getCouponId())); + priceCalculate.setPromotions(new ArrayList<>()); + // 创建它的 OrderItem 属性 + Map skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(), + PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount); + skuList.forEach(sku -> { + Integer count = skuIdCountMap.get(sku.getId()); + PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem().setCount(count) + .setOriginalPrice(sku.getPrice()).setTotalOriginalPrice(sku.getPrice() * count).setTotalPromotionPrice(0); + orderItem.setTotalPresentPrice(orderItem.getTotalPresentPrice()).setPresentPrice(orderItem.getOriginalPrice()) + .setTotalPayPrice(orderItem.getTotalPayPrice()); + priceCalculate.getOrder().getItems().add(orderItem); + }); + return priceCalculate; + } + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceService.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceService.java new file mode 100644 index 000000000..9158199d9 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceService.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.market.service.price; + +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; + +/** + * 价格计算 Service 接口 + * + * @author 芋道源码 + */ +public interface PriceService { + + /** + * 计算商品的价格 + * + * @param calculateReqDTO 价格请求 + * @return 价格相应 + */ + PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO); + +} diff --git a/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceServiceImpl.java b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceServiceImpl.java new file mode 100644 index 000000000..9c6649ec1 --- /dev/null +++ b/yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceServiceImpl.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.market.service.price; + +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; +import cn.iocoder.yudao.module.market.convert.price.PriceConvert; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; + +/** + * 价格计算 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class PriceServiceImpl implements PriceService { + + @Resource + private ProductSkuApi productSkuApi; + + @Override + public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) { + // 获得商品 SKU 数组 + List skuList = checkProductSkus(calculateReqDTO); + // 初始化 PriceCalculateRespDTO 对象 + PriceCalculateRespDTO priceCalculate = PriceConvert.INSTANCE.convert(calculateReqDTO, skuList); + + // 计算【限时折扣】促销 TODO 待实现 + // 计算【满减送】促销 TODO 待实现 + // 计算【优惠劵】促销 TODO 待实现 + return priceCalculate; + } + + private List checkProductSkus(PriceCalculateReqDTO calculateReqDTO) { + // 获得商品 SKU 数组 + Map skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(), + PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount); + List skus = productSkuApi.getSkuList(skuIdCountMap.keySet()); + + // 校验商品 SKU + skus.forEach(sku -> { + Integer count = skuIdCountMap.get(sku.getId()); + if (count == null) { + throw exception(SKU_NOT_EXISTS); + } + if (count > sku.getStock()) { + throw exception(SKU_STOCK_NOT_ENOUGH); + } + }); + return skus; + } + +} diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java index b3915407f..1c69ea490 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java @@ -1,25 +1,34 @@ package cn.iocoder.yudao.module.product.api.sku; import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import java.util.Collection; import java.util.List; /** + * 商品 SKU API 接口 + * * @author LeeYan9 * @since 2022-08-26 */ public interface ProductSkuApi { + /** + * 查询 SKU 信息 + * + * @param id SKU 编号 + * @return SKU 信息 + */ + ProductSkuRespDTO getSku(Long id); /** - * 根据skuId列表 查询sku信息 + * 批量查询 SKU 数组 * - * @param skuIds sku ID列表 - * @return sku信息列表 + * @param ids SKU 编号列表 + * @return SKU 数组 */ - List getSkusByIds(Collection skuIds); + List getSkuList(Collection ids); /** * 批量扣减sku库存 @@ -27,4 +36,5 @@ public interface ProductSkuApi { * @param batchReqDTO sku库存信息列表 */ void decrementStockBatch(SkuDecrementStockBatchReqDTO batchReqDTO); + } diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/SkuInfoRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java similarity index 95% rename from yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/SkuInfoRespDTO.java rename to yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java index f9d349e48..4b324149b 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/SkuInfoRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java @@ -6,11 +6,13 @@ import lombok.Data; import java.util.List; /** + * 商品 SKU 信息 Response DTO + * * @author LeeYan9 * @since 2022-08-26 */ @Data -public class SkuInfoRespDTO { +public class ProductSkuRespDTO { /** * 商品 SKU 编号,自增 diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java index 5dc2bf4cf..461fbe935 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java @@ -1,23 +1,24 @@ package cn.iocoder.yudao.module.product.api.spu; -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; import java.util.Collection; import java.util.List; /** + * 商品 SPU API 接口 + * * @author LeeYan9 * @since 2022-08-26 */ public interface ProductSpuApi { - /** - * 根据spuId列表 查询spu信息 + * 批量查询 SPU 数组 * - * @param spuIds spu ID列表 - * @return spu信息列表 + * @param ids SPU 编号列表 + * @return SPU 数组 */ - List getSpusByIds(Collection spuIds); + List getSpuList(Collection ids); + } diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java index 6d0206b7d..4392d9ad0 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.product.api.spu.dto; -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; import lombok.Data; @@ -80,25 +80,25 @@ public class SpuInfoRespDTO { /** * 最小价格,单位使用:分 *

- * 基于其对应的 {@link SkuInfoRespDTO#getPrice()} 最小值 + * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最小值 */ private Integer minPrice; /** * 最大价格,单位使用:分 *

- * 基于其对应的 {@link SkuInfoRespDTO#getPrice()} 最大值 + * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最大值 */ private Integer maxPrice; /** * 市场价,单位使用:分 *

- * 基于其对应的 {@link SkuInfoRespDTO#getMarketPrice()} 最大值 + * 基于其对应的 {@link ProductSkuRespDTO#getMarketPrice()} 最大值 */ private Integer marketPrice; /** * 总库存 *

- * 基于其对应的 {@link SkuInfoRespDTO#getStock()} 求和 + * 基于其对应的 {@link ProductSkuRespDTO#getStock()} 求和 */ private Integer totalStock; /** diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java index 801e2dd51..a3d64d42c 100644 --- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java @@ -36,5 +36,6 @@ public interface ErrorCodeConstants { ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复"); ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其规格数必须一致"); ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复"); + ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足"); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java index 22636826b..dad17e9ec 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java @@ -1,21 +1,38 @@ package cn.iocoder.yudao.module.product.api.sku; import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import org.springframework.stereotype.Service; +import javax.annotation.Resource; import java.util.Collection; import java.util.List; /** - * todo 注释 + * 商品 SKU API 实现类 + * + * @author 芋道源码 + * @since 2022-08-26 */ @Service public class ProductSkuApiImpl implements ProductSkuApi { + @Resource + private ProductSkuService productSkuService; + @Override - public List getSkusByIds(Collection skuIds) { - return null; + public ProductSkuRespDTO getSku(Long id) { + ProductSkuDO skuDO = productSkuService.getSku(id); + return ProductSkuConvert.INSTANCE.convert02(skuDO); + } + + @Override + public List getSkuList(Collection ids) { + List list = productSkuService.getSkuList(ids); + return ProductSkuConvert.INSTANCE.convertList02(list); } @Override diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java index 8f651f395..438ff18bf 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java @@ -7,13 +7,16 @@ import java.util.Collection; import java.util.List; /** - * todo 注释 + * 商品 SPU API 实现类 + * + * @author LeeYan9 + * @since 2022-08-26 */ @Service public class ProductSpuApiImpl implements ProductSpuApi { @Override - public List getSpusByIds(Collection spuIds) { + public List getSpuList(Collection spuIds) { return null; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java index 43f67ee53..45cb447b8 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java @@ -33,7 +33,7 @@ public class ProductSkuBaseVO { @ApiModelProperty(value = "条形码", example = "haha") private String barCode; - @ApiModelProperty(value = "图片地址") + @ApiModelProperty(value = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png") @NotNull(message = "图片地址不能为空") private String picUrl; diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java index 0ee468d36..7450da653 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java @@ -1,10 +1,10 @@ package cn.iocoder.yudao.module.product.convert.sku; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; import java.util.List; @@ -21,11 +21,14 @@ public interface ProductSkuConvert { ProductSkuDO convert(ProductSkuCreateOrUpdateReqVO bean); - @Mapping(source = "properties", target = "properties") ProductSkuRespVO convert(ProductSkuDO bean); List convertList(List list); List convertSkuDOList(List list); + ProductSkuRespDTO convert02(ProductSkuDO bean); + + List convertList02(List list); + } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java similarity index 61% rename from yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/enums/ErrorCodeConstants.java rename to yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 5bdc0ff82..bb03bd8d0 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -1,23 +1,23 @@ -package cn.iocoder.yudao.module.trade.enums.enums; +package cn.iocoder.yudao.module.trade.enums; import cn.iocoder.yudao.framework.common.exception.ErrorCode; /** - * Trade-Order 错误码 Core 枚举类 - *

- * Trade-Order 系统,使用 1-011-000-000 段 + * 交易 错误码枚举类 + * 交易系统,使用 1-011-000-000 段 * * @author LeeYan9 * @since 2022-08-26 */ public interface ErrorCodeConstants { - /** - * ========== Order 模块 1-011-000-000 ========== - */ + // ========== Order 模块 1-011-000-000 ========== ErrorCode ORDER_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品不存在"); ErrorCode ORDER_SPU_NOT_SALE = new ErrorCode(1011000002, "商品不可售卖"); ErrorCode ORDER_SKU_NOT_SALE = new ErrorCode(1011000003, "商品Sku不可售卖"); ErrorCode ORDER_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品库存不足"); + // ========== Cart 模块 1-011-001-000 ========== + ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1001001000, "购物车项不存在"); + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java new file mode 100644 index 000000000..08acfdbca --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java @@ -0,0 +1,4 @@ +/** + * 基础包,放一些通用的 VO 类 + */ +package cn.iocoder.yudao.module.trade.controller.app.base; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java new file mode 100644 index 000000000..e116f5888 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.controller.app.base.property; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel("用户 App - 规格 + 规格值 Response VO") +@Data +public class AppProductPropertyValueDetailRespVO { + + @ApiModelProperty(value = "属性的编号", required = true, example = "1") + private Long propertyId; + + @ApiModelProperty(value = "属性的名称", required = true, example = "颜色") + private String propertyName; + + @ApiModelProperty(value = "属性值的编号", required = true, example = "1024") + private Long valueId; + + @ApiModelProperty(value = "属性值的名称", required = true, example = "红色") + private String valueName; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java new file mode 100644 index 000000000..ed666a9c8 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.trade.controller.app.base.sku; + +import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 商品 SKU 基础 Response VO + * + * @author 芋道源码 + */ +@Data +public class AppProductSkuBaseRespVO { + + @ApiModelProperty(value = "主键", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "商品 SKU 名字", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "图片地址", example = "https://www.iocoder.cn/xx.png") + private String picUrl; + + @ApiModelProperty(value = "库存", required = true, example = "1") + private Integer stock; + + /** + * 规格数组 + */ + private List properties; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java new file mode 100644 index 000000000..c7d9f236f --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.trade.controller.app.base.spu; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 商品 SPU 基础 Response VO + * + * @author 芋道源码 + */ +@Data +public class AppProductSpuBaseRespVO { + + @ApiModelProperty(value = "主键", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "商品 SPU 名字", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = "商品主图地址", example = "https://www.iocoder.cn/xx.png") + private List picUrls; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/CartController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/CartController.java deleted file mode 100644 index 91e51dfd5..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/CartController.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.trade.controller.app.cart; - -import io.swagger.annotations.Api; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Api(tags = "购物车 API") -@RestController -@RequestMapping("/cart") -@Validated -public class CartController { - -// @Autowired -// private CartManager cartManager; -// -// @PostMapping("add") -// @ApiOperation("添加商品到购物车") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "skuId", value = "商品 SKU 编号", required = true, example = "1"), -// @ApiImplicitParam(name = "quantity", value = "增加数量", required = true, example = "1024") -// }) -// @RequiresAuthenticate -// public CommonResult addCartItem(@RequestParam("skuId") Integer skuId, -// @RequestParam("quantity") Integer quantity) { -// cartManager.addCartItem(UserSecurityContextHolder.getUserId(), skuId, quantity); -// return success(true); -// } -// -// @GetMapping("sum-quantity") -// @ApiOperation("查询用户在购物车中的商品数量") -// @RequiresAuthenticate -// public CommonResult sumCartItemQuantity() { -// return success(cartManager.sumCartItemQuantity(UserSecurityContextHolder.getUserId())); -// } -// -// @GetMapping("/get-detail") -// @ApiOperation("查询用户的购物车的商品列表") -// @RequiresAuthenticate -// public CommonResult getCartDetail() { -// return success(cartManager.getCartDetail(UserSecurityContextHolder.getUserId())); -// } -// -// @PostMapping("update-quantity") -// @ApiOperation("更新购物车商品数量") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "skuId", value = "商品 SKU 编号", required = true, example = "1"), -// @ApiImplicitParam(name = "quantity", value = "增加数量", required = true, example = "1024") -// }) -// @RequiresAuthenticate -// public CommonResult updateCartItemQuantity(@RequestParam("skuId") Integer skuId, -// @RequestParam("quantity") Integer quantity) { -// cartManager.updateCartItemQuantity(UserSecurityContextHolder.getUserId(), skuId, quantity); -// return success(true); -// } -// -// @PostMapping("update-selected") -// @ApiOperation("更新购物车商品是否选中") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "skuIds", value = "商品 SKU 编号数组", required = true, example = "1,3"), -// @ApiImplicitParam(name = "selected", value = "是否选中", required = true, example = "true") -// }) -// @RequiresAuthenticate -// public CommonResult updateCartItemSelected(@RequestParam("skuIds") Set skuIds, -// @RequestParam("selected") Boolean selected) { -// cartManager.updateCartItemSelected(UserSecurityContextHolder.getUserId(), skuIds, selected); -// // 获得目前购物车明细 -// return success(true); -// } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http new file mode 100644 index 000000000..3ce8797fc --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http @@ -0,0 +1,47 @@ +### 请求 /trade/cart/add-count 接口 => 成功 +POST {{appApi}}/trade/cart/add-count +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} +Content-Type: application/json + +{ + "skuId": 1, + "count": 1 +} + +### 请求 /trade/cart/update-count 接口 => 成功 +PUT {{appApi}}/trade/cart/update-count +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} +Content-Type: application/json + +{ + "skuId": 1, + "count": 5 +} + +### 请求 /trade/cart/update-selected 接口 => 成功 +PUT {{appApi}}/trade/cart/update-selected +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} +Content-Type: application/json + +{ + "skuIds": [1], + "selected": false +} + +### 请求 /trade/cart/delete 接口 => 成功 +DELETE {{appApi}}/trade/cart/delete?skuIds=1 +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /trade/cart/get-count 接口 => 成功 +GET {{appApi}}/trade/cart/get-count +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} + +### 请求 /trade/cart/get-detail 接口 => 成功 +GET {{appApi}}/trade/cart/get-detail +tenant-id: {{appTenentId}} +Authorization: Bearer {{appToken}} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java new file mode 100644 index 000000000..fa12e2f09 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Api(tags = "用户 App - 购物车") +@RestController +@RequestMapping("/trade/cart") +@RequiredArgsConstructor +@Validated +@Slf4j +public class TradeCartController { + + @Resource + private TradeCartService cartService; + + @PostMapping("/add-count") + @ApiOperation("添加商品到购物车") + @PreAuthenticated + public CommonResult addCartItemCount(@Valid @RequestBody AppTradeCartItemAddCountReqVO addCountReqVO) { + cartService.addCartItemCount(getLoginUserId(), addCountReqVO); + return success(true); + } + + @PutMapping("update-count") + @ApiOperation("更新购物车商品数量") + @PreAuthenticated + public CommonResult updateCartItemQuantity(@Valid @RequestBody AppTradeCartItemUpdateCountReqVO updateCountReqVO) { + cartService.updateCartItemCount(getLoginUserId(), updateCountReqVO); + return success(true); + } + + @PutMapping("update-selected") + @ApiOperation("更新购物车商品是否选中") + @PreAuthenticated + public CommonResult updateCartItemSelected(@Valid @RequestBody AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { + cartService.updateCartItemSelected(getLoginUserId(), updateSelectedReqVO); + // 获得目前购物车明细 + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除购物车商品") + @ApiImplicitParam(name = "skuId", value = "商品 SKU 编号的数组", required = true, example = "1024,2048", dataTypeClass = List.class) + @PreAuthenticated + public CommonResult deleteCartItem(@RequestParam("skuIds") List skuIds) { + cartService.deleteCartItems(getLoginUserId(), skuIds); + return success(true); + } + + @GetMapping("get-count") + @ApiOperation("查询用户在购物车中的商品数量") + @PreAuthenticated + public CommonResult getCartCount() { + return success(cartService.getCartCount(getLoginUserId())); + } + + @GetMapping("/get-detail") + @ApiOperation("查询用户的购物车的详情") + @PreAuthenticated + public CommonResult getCartDetail() { + return success(cartService.getCartDetail(getLoginUserId())); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java new file mode 100644 index 000000000..5656c3d69 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@ApiModel(value = "用户 App - 用户的购物车明细 Response VO") +@Data +public class AppTradeCartDetailRespVO { + + /** + * 商品分组数组 + */ + private List itemGroups; + + /** + * 费用 + */ + private Order order; + + @ApiModel(value = "商品分组", description = "多个商品,参加同一个活动,从而形成分组") + @Data + public static class ItemGroup { + + /** + * 商品数组 + */ + private List items; + /** + * 营销活动,订单级别 + */ + private Promotion promotion; + + } + + @ApiModel(value = "商品 SKU") + @Data + public static class Sku extends AppProductSkuBaseRespVO { + + /** + * SPU 信息 + */ + private AppProductSkuBaseRespVO spu; + + // ========== 购物车相关的字段 ========== + + @ApiModelProperty(value = "商品数量", required = true, example = "1") + private Integer count; + @ApiModelProperty(value = "是否选中", required = true, example = "true") + private Boolean selected; + + // ========== 价格相关的字段,对应 PriceCalculateRespDTO.OrderItem 的属性 ========== + + // TODO 芋艿:后续可以去除一些无用的字段 + + @ApiModelProperty(value = "商品原价(单)", required = true, example = "100") + private Integer originalPrice; + @ApiModelProperty(value = "商品原价(总)", required = true, example = "200") + private Integer totalOriginalPrice; + @ApiModelProperty(value = "商品级优惠(总)", required = true, example = "300") + private Integer totalPromotionPrice; + @ApiModelProperty(value = "最终购买金额(总)", required = true, example = "400") + private Integer totalPresentPrice; + @ApiModelProperty(value = "最终购买金额(单)", required = true, example = "500") + private Integer presentPrice; + @ApiModelProperty(value = "应付金额(总)", required = true, example = "600") + private Integer totalPayPrice; + + // ========== 营销相关的字段 ========== + /** + * 营销活动,商品级别 + */ + private Promotion promotion; + + } + + @ApiModel(value = "订单", description = "对应 PriceCalculateRespDTO.Order 类,用于费用(合计)") + @Data + public static class Order { + + // TODO 芋艿:后续可以去除一些无用的字段 + + @ApiModelProperty(value = "商品原价(总)", required = true, example = "100") + private Integer skuOriginalPrice; + @ApiModelProperty(value = "商品优惠(总)", required = true, example = "200") + private Integer skuPromotionPrice; + @ApiModelProperty(value = "订单优惠(总)", required = true, example = "300") + private Integer orderPromotionPrice; + @ApiModelProperty(value = "运费金额", required = true, example = "400") + private Integer deliveryPrice; + @ApiModelProperty(value = "应付金额(总)", required = true, example = "500") + private Integer payPrice; + + } + + @ApiModel(value = "营销活动", description = "对应 PriceCalculateRespDTO.Promotion 类的属性") + @Data + public static class Promotion { + + @ApiModelProperty(value = "营销编号", required = true, example = "1024", notes = "营销活动的编号、优惠劵的编号") + private Long id; + @ApiModelProperty(value = "营销名字", required = true, example = "xx 活动") + private String name; + @ApiModelProperty(value = "营销类型", required = true, example = "1", notes = "参见 PromotionTypeEnum 枚举类") + private Integer type; + + // ========== 匹配情况 ========== + @ApiModelProperty(value = "是否满足优惠条件", required = true, example = "true") + private Boolean meet; + @ApiModelProperty(value = "满足条件的提示", required = true, example = "圣诞价:省 150.00 元") + private String meetTip; + + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java new file mode 100644 index 000000000..c3103dcce --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@ApiModel(value = "用户 App - 购物车添加购物项 Request VO") +@Data +public class AppTradeCartItemAddCountReqVO { + + @ApiModelProperty(value = "商品 SKU 编号", required = true,example = "1024") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @ApiModelProperty(value = "商品数量", required = true, example = "1", notes = "注意,这是新增数量") + @NotNull(message = "数量不能为空") + @Min(message = "数量必须大于 0", value = 1L) + private Integer count; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java new file mode 100644 index 000000000..6beb09379 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +@ApiModel(value = "用户 App - 购物车更新数量 Request VO") +@Data +public class AppTradeCartItemUpdateCountReqVO { + + @ApiModelProperty(value = "商品 SKU 编号", required = true, example = "1024") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @ApiModelProperty(value = "商品数量", required = true, example = "1") + @NotNull(message = "数量不能为空") + @Min(message = "数量必须大于 0", value = 1L) + private Integer count; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java new file mode 100644 index 000000000..cc7bf6f03 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.Collection; + +@ApiModel(value = "用户 App - 购物车更新是否选中 Request VO") +@Data +public class AppTradeCartItemUpdateSelectedReqVO { + + @ApiModelProperty(value = "商品 SKU 编号列表", required = true, example = "1024,2048") + @NotNull(message = "商品 SKU 编号列表不能为空") + private Collection skuIds; + + @ApiModelProperty(value = "是否选中", required = true, example = "true") + @NotNull(message = "是否选中不能为空") + private Boolean selected; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/CartDetailVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/CartDetailVO.java deleted file mode 100644 index 403efbebe..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/CartDetailVO.java +++ /dev/null @@ -1,211 +0,0 @@ -package cn.iocoder.yudao.module.trade.controller.app.cart.vo; - -import io.swagger.annotations.ApiModel; -import lombok.Data; -import lombok.experimental.Accessors; - -import java.util.List; - -@ApiModel(value = "用户的购物车明细 Response VO") // TODO 芋艿:swagger 文档完善 -@Data -@Accessors(chain = true) -public class CartDetailVO { - - /** - * 商品分组数组 - */ - private List itemGroups; - /** - * 费用 - */ - private Fee fee; - - /** - * 商品分组 - * - * 多个商品,参加同一个活动,从而形成分组。 - */ - @Data - @Accessors(chain = true) - public static class ItemGroup { - -// /** -// * 优惠活动 -// */ -// private PromotionActivityRespDTO activity; // TODO 芋艿,偷懒 - /** - * 促销减少的金额 - * - * 1. 若未参与促销活动,或不满足促销条件,返回 null - * 2. 该金额,已经分摊到每个 Item 的 discountTotal ,需要注意。 - */ - private Integer activityDiscountTotal; - /** - * 商品数组 - */ - private List items; - - } - - @Data - @Accessors(chain = true) - public static class Sku { - - // SKU 自带信息 - /** - * sku 编号 - */ - private Integer id; - /** - * SPU 信息 - */ - private Spu spu; - /** - * 图片地址 - */ - private String picURL; -// /** -// * 规格值数组 -// */ -// private List attrs; // TODO 后面改下 - /** - * 价格,单位:分 - */ - private Integer price; - /** - * 库存数量 - */ - private Integer quantity; - - // 非 SKU 自带信息 - - /** - * 购买数量 - */ - private Integer buyQuantity; - /** - * 是否选中 - */ - private Boolean selected; -// /** -// * 优惠活动 -// */ -// private PromotionActivityRespDTO activity; // TODO 芋艿,偷懒 - /** - * 原始单价,单位:分。 - */ - private Integer originPrice; - /** - * 购买单价,单位:分 - */ - private Integer buyPrice; - /** - * 最终价格,单位:分。 - */ - private Integer presentPrice; - /** - * 购买总金额,单位:分 - * - * 用途类似 {@link #presentTotal} - */ - private Integer buyTotal; - /** - * 优惠总金额,单位:分。 - */ - private Integer discountTotal; - /** - * 最终总金额,单位:分。 - * - * 注意,presentPrice * quantity 不一定等于 presentTotal 。 - * 因为,存在无法整除的情况。 - * 举个例子,presentPrice = 8.33 ,quantity = 3 的情况,presentTotal 有可能是 24.99 ,也可能是 25 。 - * 所以,需要存储一个该字段。 - */ - private Integer presentTotal; - - } - - @Data - @Accessors(chain = true) - public static class Spu { - - /** - * SPU 编号 - */ - private Integer id; - - // ========== 基本信息 ========= - /** - * SPU 名字 - */ - private String name; - /** - * 分类编号 - */ - private Integer cid; - /** - * 商品主图地址 - * - * 数组,以逗号分隔 - * - * 建议尺寸:800*800像素,你可以拖拽图片调整顺序,最多上传15张 - */ - private List picUrls; - - } - - /** - * 费用(合计) - */ - @Data - @Accessors(chain = true) - public static class Fee { - - /** - * 购买总价 - */ - private Integer buyTotal; - /** - * 优惠总价 - * - * 注意,满多少元包邮,不算在优惠中。 - */ - private Integer discountTotal; - /** - * 邮费 - */ - private Integer postageTotal; - /** - * 最终价格 - * - * 计算公式 = 总价 - 优惠总价 + 邮费 - */ - private Integer presentTotal; - - public Fee() { - } - - public Fee(Integer buyTotal, Integer discountTotal, Integer postageTotal, Integer presentTotal) { - this.buyTotal = buyTotal; - this.discountTotal = discountTotal; - this.postageTotal = postageTotal; - this.presentTotal = presentTotal; - } - - } - - /** - * 邮费信息 TODO 芋艿,未完成 - */ - @Data - @Accessors(chain = true) - public static class Postage { - - /** - * 需要满足多少钱,可以包邮。单位:分 - */ - private Integer threshold; - - } - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 7b7ed4b83..99f63527f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -60,8 +60,8 @@ public class AppTradeOrderController { @GetMapping("/get") @ApiOperation("获得交易订单") - @ApiImplicitParam(name = "tradeOrderId", value = "交易订单编号", required = true) - public CommonResult getTradeOrder(@RequestParam("tradeOrderId") Integer tradeOrderId) { + @ApiImplicitParam(name = "id", value = "交易订单编号", required = true, dataTypeClass = Long.class) + public CommonResult getTradeOrder(@RequestParam("id") Integer id) { // return success(tradeOrderService.getTradeOrder(tradeOrderId)); return null; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java new file mode 100644 index 000000000..a3f6d47dc --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.trade.convert.cart; + +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Mapper +public interface TradeCartConvert { + + TradeCartConvert INSTANCE = Mappers.getMapper(TradeCartConvert.class); + + default AppTradeCartDetailRespVO buildEmptyAppTradeCartDetailRespVO() { + return new AppTradeCartDetailRespVO().setItemGroups(Collections.emptyList()) + .setOrder(new AppTradeCartDetailRespVO.Order().setSkuOriginalPrice(0).setSkuPromotionPrice(0) + .setOrderPromotionPrice(0).setDeliveryPrice(0).setPayPrice(0)); + } + + default PriceCalculateReqDTO convert(Long userId, List cartItems) { + return new PriceCalculateReqDTO().setUserId(userId) + .setItems(convertList(cartItems, cartItem -> new PriceCalculateReqDTO.Item().setSkuId(cartItem.getSkuId()) + .setCount(cartItem.getSelected() ? cartItem.getCount() : 0))); + } + + // ========== AppTradeCartDetailRespVO 相关 ========== + + AppTradeCartDetailRespVO.Promotion convert(PriceCalculateRespDTO.Promotion bean); + + @Mappings({ + @Mapping(source = "cartItem.count", target = "count") + }) + AppTradeCartDetailRespVO.Sku convert(PriceCalculateRespDTO.OrderItem orderItem, TradeCartItemDO cartItem); + + AppTradeCartDetailRespVO.Order convert(PriceCalculateRespDTO.Order bean); + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java index 23113f9f3..d9e8149a8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java @@ -29,7 +29,7 @@ public interface TradeOrderItemConvert { @Mapping(source = "tradeOrder.userId", target = "userId"), @Mapping(source = "tradeOrder.orderId", target = "orderId") }) - default List convertList(TradeOrderDO tradeOrder, List items) { + default List convertList(TradeOrderDO tradeOrder, List items) { // TODO @Com: Mapstruct 生成会报错 throw new UnsupportedOperationException("无法实现"); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java index fffc6fa42..7aa4f554b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java @@ -7,6 +7,7 @@ import org.mapstruct.factory.Mappers; import java.util.List; +// TODO @LeeYan9:挪到 OrderConvert 那 /** * @author LeeYan9 * @since 2022-08-26 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java similarity index 91% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartItemDO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java index b92ca8b54..05fbb801d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java @@ -6,16 +6,16 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; -import java.util.Date; - /** * 购物车的商品信息 DO + * + * @author 芋道源码 */ @TableName("trade_cart_item") @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) -public class CartItemDO extends BaseDO { +public class TradeCartItemDO extends BaseDO { // ========= 基础字段 BEGIN ========= @@ -27,10 +27,6 @@ public class CartItemDO extends BaseDO { * 是否选中 */ private Boolean selected; - /** - * 购物时间 - */ - private Date buyTime; // basket_date // ========= 基础字段 END ========= @@ -62,7 +58,7 @@ public class CartItemDO extends BaseDO { /** * 商品购买数量 */ - private Integer stock; + private Integer count; // ========= 商品信息 END ========= diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java new file mode 100644 index 000000000..fa6adbf41 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.trade.dal.mysql.cart; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Mapper +public interface TradeCartItemMapper extends BaseMapperX { + + default TradeCartItemDO selectByUserIdAndSkuId(Long userId, Long skuId) { + return selectOne(TradeCartItemDO::getUserId, userId, + TradeCartItemDO::getSkuId, skuId); + } + + default List selectListByUserIdAndSkuIds(Long userId, Collection skuIds) { + return selectList(new LambdaQueryWrapper().eq(TradeCartItemDO::getUserId, userId) + .in(TradeCartItemDO::getSkuId, skuIds)); + } + + default void updateByIds(Collection ids, TradeCartItemDO updateObject) { + update(updateObject, new LambdaQueryWrapper().in(TradeCartItemDO::getId, ids)); + } + + default Integer selectSumByUserId(Long userId) { + // SQL sum 查询 + List> result = selectMaps(new QueryWrapper() + .select("SUM(count) AS sumCount") + .eq("user_id", userId)); + // 获得数量 + return CollUtil.isNotEmpty(result) ? MapUtil.getInt(result.get(0), "sumCount") : 0; + } + + default List selectListByUserId(Long userId, Boolean selected) { + return selectList(new LambdaQueryWrapperX().eq(TradeCartItemDO::getUserId, userId) + .eqIfPresent(TradeCartItemDO::getSelected, selected)); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java new file mode 100644 index 000000000..3f46f5102 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.trade.service.cart; + +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; + +import javax.validation.Valid; +import java.util.Collection; + +/** + * 购物车 Service 接口 + * + * @author 芋道源码 + */ +public interface TradeCartService { + + /** + * 添加商品到购物车 + * + * @param userId 用户编号 + * @param addCountReqVO 添加信息 + */ + void addCartItemCount(Long userId, @Valid AppTradeCartItemAddCountReqVO addCountReqVO); + + /** + * 更新购物车商品数量 + * + * @param userId 用户编号 + * @param updateCountReqVO 更新信息 + */ + void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO); + + /** + * 更新购物车商品是否选中 + * + * @param userId 用户编号 + * @param updateSelectedReqVO 更新信息 + */ + void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO); + + /** + * 删除购物车商品 + * + * @param userId 用户编号 + * @param skuIds SKU 编号的数组 + */ + void deleteCartItems(Long userId, Collection skuIds); + + /** + * 查询用户在购物车中的商品数量 + * + * @param userId 用户编号 + * @return 商品数量 + */ + Integer getCartCount(Long userId); + + /** + * 查询用户的购物车详情 + * + * @param userId 用户编号 + * @return 购物车详情 + */ + AppTradeCartDetailRespVO getCartDetail(Long userId); + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java new file mode 100644 index 000000000..fa58ac215 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java @@ -0,0 +1,184 @@ +package cn.iocoder.yudao.module.trade.service.cart; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.market.api.price.PriceApi; +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; +import cn.iocoder.yudao.module.market.enums.common.PromotionLevelEnum; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; +import cn.iocoder.yudao.module.trade.convert.cart.TradeCartConvert; +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; +import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartItemMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.CARD_ITEM_NOT_FOUND; + +/** + * 购物车 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class TradeCartServiceImpl implements TradeCartService { + + @Resource + private TradeCartItemMapper cartItemMapper; + + @Resource + private ProductSkuApi productSkuApi; + @Resource + private PriceApi priceApi; + + @Override + public void addCartItemCount(Long userId, AppTradeCartItemAddCountReqVO addCountReqVO) { + Long skuId = addCountReqVO.getSkuId(); + Integer count = addCountReqVO.getCount(); + // 查询 CartItemDO + TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, addCountReqVO.getSkuId()); + + // 存在,则进行数量更新 + if (tradeItem != null) { + checkProductSku(skuId, tradeItem.getCount() + count); + cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()) + .setSelected(true).setCount(tradeItem.getCount() + count)); + return; + } + + // 不存在,则进行插入 + ProductSkuRespDTO sku = checkProductSku(skuId, count); + cartItemMapper.insert(new TradeCartItemDO().setUserId(userId).setSpuId(sku.getSpuId()).setSkuId(sku.getId()) + .setSelected(true).setCount(count)); + } + + @Override + public void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO) { + // 校验 TradeCartItemDO 存在 + TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, updateCountReqVO.getSkuId()); + if (tradeItem == null) { + throw exception(CARD_ITEM_NOT_FOUND); + } + // 校验商品 SKU + checkProductSku(updateCountReqVO.getSkuId(), updateCountReqVO.getCount()); + + // 更新数量 + cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()).setCount(updateCountReqVO.getCount())); + } + + @Override + public void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { + // 查询 CartItemDO 列表 + List cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, updateSelectedReqVO.getSkuIds()); + if (CollUtil.isEmpty(cartItems)) { + return; + } + + // 更新选中 + cartItemMapper.updateByIds(CollectionUtils.convertList(cartItems, TradeCartItemDO::getId), + new TradeCartItemDO().setSelected(updateSelectedReqVO.getSelected())); + } + + /** + * 购物车删除商品 + * + * @param userId 用户编号 + * @param skuIds 商品 SKU 编号的数组 + */ + @Override + public void deleteCartItems(Long userId, Collection skuIds) { + // 查询 CartItemDO 列表 + List cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, skuIds); + if (CollUtil.isEmpty(cartItems)) { + return; + } + + // 批量标记删除 + cartItemMapper.deleteBatchIds(CollectionUtils.convertSet(cartItems, TradeCartItemDO::getId)); + } + + @Override + public Integer getCartCount(Long userId) { + return cartItemMapper.selectSumByUserId(userId); + } + + @Override + public AppTradeCartDetailRespVO getCartDetail(Long userId) { + // 获得购物车的商品 + List cartItems = cartItemMapper.selectListByUserId(userId, null); + // 如果未空,则返回空结果 + if (CollUtil.isEmpty(cartItems)) { + return TradeCartConvert.INSTANCE.buildEmptyAppTradeCartDetailRespVO(); + } + + // 调用价格服务,计算价格 + PriceCalculateRespDTO priceCalculate = priceApi.calculatePrice(TradeCartConvert.INSTANCE.convert(userId, cartItems)); + + // 转换返回 + Map cartItemMap = convertMap(cartItems, TradeCartItemDO::getSkuId); + Map orderItemMap = convertMap(priceCalculate.getOrder().getItems(), + PriceCalculateRespDTO.OrderItem::getSkuId); + List itemGroups = new ArrayList<>(cartItems.size()); + // ① 场景一,营销活动,订单级别 TODO 芋艿:待测试 + priceCalculate.getPromotions().stream().filter(promotion -> PromotionLevelEnum.ORDER.getLevel().equals(promotion.getLevel())) + .forEach(promotion -> { + AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>()) + .setPromotion(TradeCartConvert.INSTANCE.convert(promotion)); + itemGroups.add(itemGroup); + promotion.getItems().forEach(promotionItem -> { + PriceCalculateRespDTO.OrderItem orderItem = orderItemMap.remove(promotionItem.getSkuId()); + Assert.notNull(orderItem, "商品 SKU({}) 对应的订单项不能为空", promotionItem.getSkuId()); + TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); + itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu + }); + }); + // ② 场景二,营销活动,商品级别 + orderItemMap.values().forEach(orderItem -> { + AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>(1)).setPromotion(null); + itemGroups.add(itemGroup); + TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); + itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu + }); + return new AppTradeCartDetailRespVO().setItemGroups(itemGroups) + .setOrder(TradeCartConvert.INSTANCE.convert(priceCalculate.getOrder())); + } + + /** + * 校验商品 SKU 是否合法 + * 1. 是否存在 + * 2. 是否下架 + * 3. 库存不足 + * + * @param skuId 商品 SKU 编号 + * @param count 商品数量 + * @return 商品 SKU + */ + private ProductSkuRespDTO checkProductSku(Long skuId, Integer count) { + ProductSkuRespDTO sku = productSkuApi.getSku(skuId); + if (sku == null || CommonStatusEnum.DISABLE.getStatus().equals(sku.getStatus())) { + throw exception(SKU_NOT_EXISTS); + } + if (count > sku.getStock()) { + throw exception(SKU_STOCK_NOT_ENOUGH); + } + return sku; + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 3554e7d4c..5cb9e066b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; import cn.iocoder.yudao.module.pay.api.order.PayOrderDataCreateReqDTO; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; @@ -26,7 +26,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; -import cn.iocoder.yudao.module.trade.enums.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -62,12 +62,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { List items = createReqVO.getItems(); // 商品SKU检查 sku可售状态,库存 - List skuInfos = productSkuApi.getSkusByIds(CollectionUtils.convertSet(items, Item::getSkuId)); - Map skuInfoMap = CollectionUtils.convertMap(skuInfos, SkuInfoRespDTO::getId); + List skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId)); + Map skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId); checkSaleableAndStockFromSpu(skuInfoMap, items); // 商品SPU检查 sku可售状态,库存 - List spuInfos = productSpuApi.getSpusByIds(CollectionUtils.convertSet(skuInfos, SkuInfoRespDTO::getSpuId)); + List spuInfos = productSpuApi.getSpuList(CollectionUtils.convertSet(skuInfos, ProductSkuRespDTO::getSpuId)); checkSaleableFromSpu(spuInfos); // 价格计算 @@ -79,7 +79,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { tradeOrderMapper.insert(tradeOrderDO); // 订单项信息记录 - List tradeOrderItems = TradeOrderItemConvert.INSTANCE.convertList(tradeOrderDO, priceResp.getItems()); + List tradeOrderItems = TradeOrderItemConvert.INSTANCE.convertList(tradeOrderDO, priceResp.getOrder().getItems()); //-填充订单项-SKU信息 fillItemsInfoFromSku(tradeOrderItems, skuInfoMap); tradeOrderItemMapper.insertBatch(tradeOrderItems); @@ -94,10 +94,10 @@ public class TradeOrderServiceImpl implements TradeOrderService { } private void fillItemsInfoFromSku(List tradeOrderItems, - Map spuInfos) { + Map spuInfos) { for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) { // 填充SKU信息 - SkuInfoRespDTO skuInfoRespDTO = spuInfos.get(tradeOrderItem.getSkuId()); + ProductSkuRespDTO skuInfoRespDTO = spuInfos.get(tradeOrderItem.getSkuId()); tradeOrderItem.setSpuId(skuInfoRespDTO.getSpuId()); tradeOrderItem.setPicUrl(skuInfoRespDTO.getPicUrl()); tradeOrderItem.setName(skuInfoRespDTO.getName()); @@ -116,14 +116,14 @@ public class TradeOrderServiceImpl implements TradeOrderService { } } - private void checkSaleableAndStockFromSpu(Map skuInfoMap, + private void checkSaleableAndStockFromSpu(Map skuInfoMap, List items) { // sku 不存在 if (items.size() != skuInfoMap.size()) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_FOUND); } for (Item item : items) { - SkuInfoRespDTO skuInfoDTO = skuInfoMap.get(item.getSkuId()); + ProductSkuRespDTO skuInfoDTO = skuInfoMap.get(item.getSkuId()); // sku禁用 if (!Objects.equals(CommonStatusEnum.ENABLE.getStatus(), skuInfoDTO.getStatus())) { throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_SALE); diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index c26354ead..3819b1e2a 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -173,6 +173,7 @@ logging: cn.iocoder.yudao.module.system.dal.mysql: debug cn.iocoder.yudao.module.tool.dal.mysql: debug cn.iocoder.yudao.module.member.dal.mysql: debug + cn.iocoder.yudao.module.trade.dal.mysql: debug --- #################### 微信公众号、小程序相关配置 #################### wx: From e1e55dc841df7b6ceead7f3a2ae05799050c7f95 Mon Sep 17 00:00:00 2001 From: luowenfeng <1092164058@qq.com> Date: Wed, 14 Sep 2022 11:57:30 +0800 Subject: [PATCH 03/78] =?UTF-8?q?feature(=E5=95=86=E5=93=81=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0):=20=E8=A7=84=E6=A0=BC=E8=B0=83=E6=95=B4=E8=BF=9E?= =?UTF-8?q?=E5=B8=A6=E5=95=86=E5=93=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../property/ProductPropertyController.java | 27 +++- .../ProductPropertyValueController.java | 70 ++++++++ .../vo/property/ProductPropertyBaseVO.java | 16 +- .../property/ProductPropertyCreateReqVO.java | 14 +- .../vo/property/ProductPropertyListReqVO.java | 19 +++ .../vo/property/ProductPropertyRespVO.java | 24 +++ .../property/ProductPropertyUpdateReqVO.java | 4 - .../vo/value/ProductPropertyValueBaseVO.java | 4 +- .../value/ProductPropertyValuePageReqVO.java | 31 ++++ .../admin/spu/ProductSpuController.java | 14 +- .../admin/spu/vo/ProductSpuBaseVO.java | 8 + .../admin/spu/vo/ProductSpuDetailRespVO.java | 7 + .../admin/spu/vo/ProductSpuPageReqVO.java | 27 +--- .../admin/spu/vo/ProductSpuRespVO.java | 18 --- .../property/ProductPropertyConvert.java | 8 +- .../convert/sku/ProductSkuConvert.java | 3 + .../property/ProductPropertyDO.java | 4 + .../property/ProductPropertyValueDO.java | 5 + .../property/ProductPropertyValueMapper.java | 14 +- .../dal/mysql/spu/ProductSpuMapper.java | 3 - .../property/ProductPropertyService.java | 34 ++-- .../property/ProductPropertyServiceImpl.java | 88 +++++----- .../property/ProductPropertyValueService.java | 65 ++++++++ .../ProductPropertyValueServiceImpl.java | 66 ++++++++ .../service/sku/ProductSkuServiceImpl.java | 17 +- .../service/spu/ProductSpuService.java | 13 +- .../service/spu/ProductSpuServiceImpl.java | 54 ++++--- .../src/api/mall/product/property.js | 65 ++++++++ yudao-ui-admin/src/api/mall/product/spu.js | 8 + yudao-ui-admin/src/router/index.js | 11 ++ .../src/views/mall/product/property/index.vue | 79 +++------ .../src/views/mall/product/spu/index.vue | 151 +++++++++++------- .../src/views/mall/product/spu/save.vue | 71 ++++---- 33 files changed, 705 insertions(+), 337 deletions(-) create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java create mode 100644 yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java index 7401ec744..72a8bf603 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyController.java @@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.product.controller.admin.property; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*; import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -17,6 +14,8 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.List; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Api(tags = "管理后台 - 规格名称") @@ -56,15 +55,29 @@ public class ProductPropertyController { @ApiOperation("获得规格名称") @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) @PreAuthorize("@ss.hasPermission('product:property:query')") - public CommonResult getProperty(@RequestParam("id") Long id) { + public CommonResult getProperty(@RequestParam("id") Long id) { return success(productPropertyService.getPropertyResp(id)); } + @GetMapping("/list") + @ApiOperation("获得规格名称列表") + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult> getPropertyList(@Valid ProductPropertyListReqVO listReqVO) { + return success(productPropertyService.getPropertyList(listReqVO)); + } + @GetMapping("/page") @ApiOperation("获得规格名称分页") @PreAuthorize("@ss.hasPermission('product:property:query')") - public CommonResult> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) { - return success(productPropertyService.getPropertyListPage(pageVO)); + public CommonResult> getPropertyPage(@Valid ProductPropertyPageReqVO pageVO) { + return success(productPropertyService.getPropertyPage(pageVO)); + } + + @GetMapping("/listAndValue") + @ApiOperation("获得规格名称列表") + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult> getPropertyAndValueList(@Valid ProductPropertyListReqVO listReqVO) { + return success(productPropertyService.getPropertyAndValueList(listReqVO)); } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java new file mode 100644 index 000000000..e88c91415 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/ProductPropertyValueController.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.product.controller.admin.property; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 规格值名称") +@RestController +@RequestMapping("/product/property/value") +@Validated +public class ProductPropertyValueController { + + @Resource + private ProductPropertyValueService productPropertyValueService; + + @PostMapping("/create") + @ApiOperation("创建规格名称") + @PreAuthorize("@ss.hasPermission('product:property:create')") + public CommonResult createProperty(@Valid @RequestBody ProductPropertyValueCreateReqVO createReqVO) { + return success(productPropertyValueService.createPropertyValue(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新规格名称") + @PreAuthorize("@ss.hasPermission('product:property:update')") + public CommonResult updateProperty(@Valid @RequestBody ProductPropertyValueUpdateReqVO updateReqVO) { + productPropertyValueService.updatePropertyValue(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除规格名称") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('product:property:delete')") + public CommonResult deleteProperty(@RequestParam("id") Long id) { + productPropertyValueService.deletePropertyValue(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得规格名称") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult getProperty(@RequestParam("id") Long id) { + return success(productPropertyValueService.getPropertyValue(id)); + } + + @GetMapping("/page") + @ApiOperation("获得规格名称分页") + @PreAuthorize("@ss.hasPermission('product:property:query')") + public CommonResult> getPropertyValuePage(@Valid ProductPropertyValuePageReqVO pageVO) { + return success(productPropertyValueService.getPropertyValueListPage(pageVO)); + } +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java index c900a727b..25fc4c01a 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyBaseVO.java @@ -3,21 +3,25 @@ package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; /** -* 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 -*/ + * 规格名称 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ @Data public class ProductPropertyBaseVO { @ApiModelProperty(value = "规格名称", required = true, example = "颜色") - @NotEmpty(message = "规格名称不能为空") + @NotBlank(message = "规格名称不能为空") private String name; + @ApiModelProperty(value = "备注", example = "颜色") + private String remark; + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举") - @NotEmpty(message = "状态不能为空") + @NotNull(message = "状态不能为空") private Integer status; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java index c0e6b9da2..8dfd58a5d 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyCreateReqVO.java @@ -1,11 +1,9 @@ package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; -import lombok.*; -import io.swagger.annotations.*; - -import javax.validation.constraints.NotNull; -import java.util.List; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; @ApiModel("管理后台 - 规格名称创建 Request VO") @Data @@ -13,9 +11,5 @@ import java.util.List; @ToString(callSuper = true) public class ProductPropertyCreateReqVO extends ProductPropertyBaseVO { - // TODO @Luowenfeng:规格值的 CRUD 可以单独;前端 + 后端,改成类似字典类型、字典数据的这种交互;在加一个 ProductPropertyValueController - @ApiModelProperty(value = "属性值") - @NotNull(message = "属性值不能为空") - List propertyValueList; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java new file mode 100644 index 000000000..314288ffb --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyListReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.ToString; + +@ApiModel("管理后台 - 规格名称 List Request VO") +@Data +@ToString(callSuper = true) +public class ProductPropertyListReqVO { + + @ApiModelProperty(value = "规格名称", example = "颜色") + private String name; + + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举") + private Integer status; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java new file mode 100644 index 000000000..e42cfaba0 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.property; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("管理后台 - 规格 + 规格值 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductPropertyRespVO extends ProductPropertyBaseVO { + + @ApiModelProperty(value = "规格的编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java index f4b9d695a..f4630d874 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/property/ProductPropertyUpdateReqVO.java @@ -16,8 +16,4 @@ public class ProductPropertyUpdateReqVO extends ProductPropertyBaseVO { @NotNull(message = "主键不能为空") private Long id; - @ApiModelProperty(value = "属性值") - @NotNull(message = "属性值不能为空") - List propertyValueList; - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java index 1e0708009..c289e7c61 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValueBaseVO.java @@ -22,7 +22,9 @@ public class ProductPropertyValueBaseVO { private String name; @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举") - @NotEmpty(message = "状态不能为空") + @NotNull(message = "状态不能为空") private Integer status; + @ApiModelProperty(value = "备注", example = "颜色") + private String remark; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java new file mode 100644 index 000000000..ae77d822b --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/property/vo/value/ProductPropertyValuePageReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.product.controller.admin.property.vo.value; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotEmpty; +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 规格名称值分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductPropertyValuePageReqVO extends PageParam { + + @ApiModelProperty(value = "规格id", example = "1024") + private String propertyId; + + @ApiModelProperty(value = "规格值", example = "红色") + private String name; + + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举") + private Integer status; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java index ddae45dc2..0e5f57ec6 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java @@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.product.controller.admin.spu; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; @@ -56,6 +53,14 @@ public class ProductSpuController { return success(true); } + @GetMapping("/get/detail") + @ApiOperation("获得商品 SPU") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('product:spu:query')") + public CommonResult getSpuDetail(@RequestParam("id") Long id) { + return success(spuService.getSpuDetail(id)); + } + @GetMapping("/get") @ApiOperation("获得商品 SPU") @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) @@ -64,7 +69,6 @@ public class ProductSpuController { return success(spuService.getSpu(id)); } - // TODO @luowenfeng:新增 get-detail,返回 SpuDetailRespVO @GetMapping("/list") @ApiOperation("获得商品 SPU 列表") diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java index ec58bab76..826cdd6c4 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.product.controller.admin.spu.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; import io.swagger.annotations.ApiModelProperty; @@ -67,6 +68,9 @@ public class ProductSpuBaseVO { @ApiModelProperty(value = "库存", required = true, example = "true") private Integer totalStock; + @ApiModelProperty(value = "市场价", example = "1024") + private Integer marketPrice; + @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024") private Integer minPrice; @@ -75,10 +79,14 @@ public class ProductSpuBaseVO { // ========== 统计相关字段 ========= + @ApiModelProperty(value = "商品销量", example = "1024") + private Integer salesCount; + @ApiModelProperty(value = "虚拟销量", required = true, example = "1024") @NotNull(message = "虚拟销量不能为空") private Integer virtualSalesCount; @ApiModelProperty(value = "点击量", example = "1024") private Integer clickCount; + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java index dafb0a680..8986a93c8 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.product.controller.admin.spu.vo; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -54,4 +55,10 @@ public class ProductSpuDetailRespVO extends ProductSpuBaseVO { } + @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]") + private List categoryIds; + + @ApiModelProperty(value = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]") + private List productPropertyViews; + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java index 36a37541b..2f0dd57e0 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java @@ -17,35 +17,16 @@ public class ProductSpuPageReqVO extends PageParam { @ApiModelProperty(value = "商品名称") private String name; - @ApiModelProperty(value = "卖点") - private String sellPoint; - - @ApiModelProperty(value = "描述") - private String description; + @ApiModelProperty(value = "商品编码", example = "yudaoyuanma") + private String code; @ApiModelProperty(value = "分类id") private Long categoryId; - @ApiModelProperty(value = "商品主图地址,* 数组,以逗号分隔,最多上传15张") - private String picUrls; - - @ApiModelProperty(value = "排序字段") - private Integer sort; - - @ApiModelProperty(value = "点赞初始人数") - private Integer likeCount; - - @ApiModelProperty(value = "价格 单位使用:分") - private Integer price; - - @ApiModelProperty(value = "库存数量") - private Integer quantity; + @ApiModelProperty(value = "商品品牌编号", example = "1") + private Long brandId; @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)") private Integer status; - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - @ApiModelProperty(value = "创建时间") - private Date[] createTime; - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java index 9db319fdc..222288770 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java @@ -1,7 +1,5 @@ package cn.iocoder.yudao.module.product.controller.admin.spu.vo; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO; -import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -9,9 +7,7 @@ import lombok.EqualsAndHashCode; import lombok.ToString; import java.util.Date; -import java.util.List; -// TODO @Luowenfeng:这个类只返回 SPU 相关的信息,删除 skus、categoryIds、productPropertyViews;明细使用 SpuDetailRespVO 替代 @ApiModel("管理后台 - 商品 SPU Response VO") @Data @EqualsAndHashCode(callSuper = true) @@ -24,18 +20,4 @@ public class ProductSpuRespVO extends ProductSpuBaseVO { @ApiModelProperty(value = "创建时间") private Date createTime; - /** - * SKU 数组 - */ - @ApiModelProperty(value = "sku 数组", example = "[{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":10}],\"price\":12,\"originalPrice\":32,\"costPrice\":22,\"barCode\":\"765670123123\",\"picUrl\":\"http://test.yudao.iocoder.cn/72938088f1ca8438837c3b51394aea43.jpg\",\"status\":0,\"id\":7,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":15},{\"propertyId\":2,\"valueId\":11}],\"price\":13,\"originalPrice\":33,\"costPrice\":23,\"barCode\":\"888788770999\",\"picUrl\":\"http://test.yudao.iocoder.cn/6b902c700e5d32e862b6fd9af2e1c0e4.jpg\",\"status\":0,\"id\":8,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":10}],\"price\":14,\"originalPrice\":34,\"costPrice\":24,\"barCode\":\"9999981212\",\"picUrl\":\"http://test.yudao.iocoder.cn/eddf3c79b1917160d94d05244e1f47da.jpg\",\"status\":0,\"id\":9,\"createTime\":1656683270000},{\"spuId\":4,\"properties\":[{\"propertyId\":3,\"valueId\":16},{\"propertyId\":2,\"valueId\":11}],\"price\":15,\"originalPrice\":35,\"costPrice\":25,\"barCode\":\"4444121212\",\"picUrl\":\"http://test.yudao.iocoder.cn/88ac3eb068ea9cfac4726879b2776ccf.jpg\",\"status\":0,\"id\":10,\"createTime\":1656683270000}]") - private List skus; - - @ApiModelProperty(value = "分类id数组,一直递归到一级父节点", example = "[1,2,4]") - private List categoryIds; - - // TODO @芋艿:再琢磨下 这个 VO 类,其实变成 SpuRespVO 内嵌的 VO 类会更好一点;然后把 SpuRespVO 改成 SpuDetailSpuVO - - @ApiModelProperty(value = "规格属性修改和详情展示组合", example = "[{\"propertyId\":2,\"name\":\"内存\",\"propertyValues\":[{\"v1\":11,\"v2\":\"64G\"},{\"v1\":10,\"v2\":\"32G\"}]},{\"propertyId\":3,\"name\":\"尺寸\",\"propertyValues\":[{\"v1\":16,\"v2\":\"6.1\"},{\"v1\":15,\"v2\":\"5.7\"}]}]") - private List productPropertyViews; - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java index 52b82a2ea..9f7c46745 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/property/ProductPropertyConvert.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.product.convert.property; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyUpdateReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; import org.mapstruct.Mapper; @@ -24,10 +24,10 @@ public interface ProductPropertyConvert { ProductPropertyDO convert(ProductPropertyUpdateReqVO bean); - ProductPropertyAndValueRespVO convert(ProductPropertyDO bean); + ProductPropertyRespVO convert(ProductPropertyDO bean); - List convertList(List list); + List convertList(List list); - PageResult convertPage(PageResult page); + PageResult convertPage(PageResult page); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java index 7450da653..bbb7e3d2c 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.product.convert.sku; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -31,4 +32,6 @@ public interface ProductSkuConvert { List convertList02(List list); + List convertList03(List list); + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java index 608b248fe..b3831491e 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyDO.java @@ -37,6 +37,10 @@ public class ProductPropertyDO extends BaseDO { * 枚举 {@link CommonStatusEnum} */ private Integer status; + /** + * 备注 + */ + private String remark; // TODO 芋艿:rule;规格属性 (发布商品时,和 SKU 关联);规格参数(搜索商品时,与 Category 关联搜索) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java index 007b95a4f..b75f0d592 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/property/ProductPropertyValueDO.java @@ -44,5 +44,10 @@ public class ProductPropertyValueDO extends BaseDO { * 枚举 {@link CommonStatusEnum} */ private Integer status; + /** + * 备注 + * + */ + private String remark; } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java index 6c5fc7570..bef38d37a 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/property/ProductPropertyValueMapper.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.product.dal.mysql.property; +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.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; import org.apache.ibatis.annotations.Mapper; @@ -16,17 +18,25 @@ import java.util.List; public interface ProductPropertyValueMapper extends BaseMapperX { // TODO @franky:方法名,selectListByXXX。mapper 的操作都是 crud - default List getPropertyValueListByPropertyId(List propertyIds){ + default List getPropertyValueListByPropertyId(List propertyIds) { // TODO @franky:调用父类的 selectList return selectList(new LambdaQueryWrapperX() .inIfPresent(ProductPropertyValueDO::getPropertyId, propertyIds)); } - default void deletePropertyValueByPropertyId(Long propertyId){ + default void deletePropertyValueByPropertyId(Long propertyId) { // TODO @franky:delete(new ) 即可 LambdaQueryWrapperX queryWrapperX = new LambdaQueryWrapperX<>(); queryWrapperX.eq(ProductPropertyValueDO::getPropertyId, propertyId) .eq(ProductPropertyValueDO::getDeleted, false); delete(queryWrapperX); } + + default PageResult selectPage(ProductPropertyValuePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ProductPropertyValueDO::getPropertyId, reqVO.getPropertyId()) + .likeIfPresent(ProductPropertyValueDO::getName, reqVO.getName()) + .eqIfPresent(ProductPropertyValueDO::getStatus, reqVO.getStatus()) + .orderByDesc(ProductPropertyValueDO::getId)); + } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java index 1755695cb..49243c8d4 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java @@ -18,11 +18,8 @@ public interface ProductSpuMapper extends BaseMapperX { default PageResult selectPage(ProductSpuPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(ProductSpuDO::getName, reqVO.getName()) - .eqIfPresent(ProductSpuDO::getSellPoint, reqVO.getSellPoint()) .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId()) - .eqIfPresent(ProductSpuDO::getPicUrls, reqVO.getPicUrls()) .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(ProductSpuDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(ProductSpuDO::getSort)); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java index a87e15d70..03c200d64 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.product.service.property; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*; import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyDO; @@ -48,35 +48,35 @@ public interface ProductPropertyService { /** * 获得规格名称列表 - * - * @param ids 编号 - * @return 规格名称列表 + * @param listReqVO 集合查询 + * @return 规格名称集合 */ - List getPropertyList(Collection ids); - - /** - * 获得规格名称分页 - * - * @param pageReqVO 分页查询 - * @return 规格名称分页 - */ - PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO); + List getPropertyList(ProductPropertyListReqVO listReqVO); /** * 获取属性及属性值列表 分页 * @param pageReqVO * @return */ - PageResult getPropertyListPage(ProductPropertyPageReqVO pageReqVO); + PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO); - ProductPropertyAndValueRespVO getPropertyResp(Long id); + + ProductPropertyRespVO getPropertyResp(Long id); /** * 根据规格属性编号的集合,获得对应的规格 + 规格值的集合 * * @param ids 规格编号的集合 - * @return 对应的规格 + 规格值的集合 + * @return 对应的规格 */ - List getPropertyAndValueList(Collection ids); + List getPropertyList(Collection ids); + + + /** + * 获得规格名称列表 + * @param listReqVO 集合查询 + * @return 规格名称集合 + */ + List getPropertyAndValueList(ProductPropertyListReqVO listReqVO); } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java index d48c8b1ff..9cce0d0b3 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.product.service.property; +import cn.hutool.core.bean.BeanUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.*; import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; @@ -46,12 +49,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { // 插入 ProductPropertyDO property = ProductPropertyConvert.INSTANCE.convert(createReqVO); productPropertyMapper.insert(property); - - //插入属性值 - List propertyValueList = createReqVO.getPropertyValueList(); - List productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList); - productPropertyValueDOList.forEach(x-> x.setPropertyId(property.getId())); - productPropertyValueMapper.insertBatch(productPropertyValueDOList); // 返回 return property.getId(); } @@ -64,12 +61,6 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { // 更新 ProductPropertyDO updateObj = ProductPropertyConvert.INSTANCE.convert(updateReqVO); productPropertyMapper.updateById(updateObj); - //更新属性值,先删后加 - productPropertyValueMapper.deletePropertyValueByPropertyId(updateReqVO.getId()); - List propertyValueList = updateReqVO.getPropertyValueList(); - List productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList); - productPropertyValueDOList.forEach(x-> x.setPropertyId(updateReqVO.getId())); - productPropertyValueMapper.insertBatch(productPropertyValueDOList); } @Override @@ -94,31 +85,28 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { } @Override - public List getPropertyList(Collection ids) { - return productPropertyMapper.selectBatchIds(ids); + public List getPropertyList(ProductPropertyListReqVO listReqVO) { + return ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectList(new LambdaQueryWrapperX() + .likeIfPresent(ProductPropertyDO::getName, listReqVO.getName()) + .eqIfPresent(ProductPropertyDO::getStatus, listReqVO.getStatus()))); } @Override - public PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO) { - return productPropertyMapper.selectPage(pageReqVO); - } - - @Override - public PageResult getPropertyListPage(ProductPropertyPageReqVO pageReqVO) { + public PageResult getPropertyPage(ProductPropertyPageReqVO pageReqVO) { //获取属性列表 PageResult pageResult = productPropertyMapper.selectPage(pageReqVO); - PageResult propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult); - List propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyAndValueRespVO::getId).collect(Collectors.toList()); - - //获取属性值列表 - List productPropertyValueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds); - List propertyValueRespVOList = ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueDOList); - //组装一对多 - propertyRespVOPageResult.getList().forEach(x->{ - Long propertyId = x.getId(); - List valueDOList = propertyValueRespVOList.stream().filter(v -> v.getPropertyId().equals(propertyId)).collect(Collectors.toList()); - x.setValues(valueDOList); - }); + PageResult propertyRespVOPageResult = ProductPropertyConvert.INSTANCE.convertPage(pageResult); +// List propertyIds = propertyRespVOPageResult.getList().stream().map(ProductPropertyAndValueRespVO::getId).collect(Collectors.toList()); +// +// //获取属性值列表 +// List productPropertyValueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(propertyIds); +// List propertyValueRespVOList = ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueDOList); +// //组装一对多 +// propertyRespVOPageResult.getList().forEach(x->{ +// Long propertyId = x.getId(); +// List valueDOList = propertyValueRespVOList.stream().filter(v -> v.getPropertyId().equals(propertyId)).collect(Collectors.toList()); +// x.setValues(valueDOList); +// }); return propertyRespVOPageResult; } @@ -127,25 +115,31 @@ public class ProductPropertyServiceImpl implements ProductPropertyService { } @Override - public ProductPropertyAndValueRespVO getPropertyResp(Long id) { + public ProductPropertyRespVO getPropertyResp(Long id) { //查询规格 ProductPropertyDO property = getProperty(id); - ProductPropertyAndValueRespVO propertyRespVO = ProductPropertyConvert.INSTANCE.convert(property); - //查询属性值 - List valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(Arrays.asList(id)); - List propertyValueRespVOS = ProductPropertyValueConvert.INSTANCE.convertList(valueDOList); - //组装 - propertyRespVO.setValues(propertyValueRespVOS); - return propertyRespVO; + return ProductPropertyConvert.INSTANCE.convert(property); } @Override - public List getPropertyAndValueList(Collection ids) { - List productPropertyRespVO = ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids)); + public List getPropertyList(Collection ids) { + return ProductPropertyConvert.INSTANCE.convertList(productPropertyMapper.selectBatchIds(ids)); + } + + @Override + public List getPropertyAndValueList(ProductPropertyListReqVO listReqVO) { + List propertyList = getPropertyList(listReqVO); + //查询属性值 - List valueDOList = productPropertyValueMapper.selectBatchIds(ids); - Map> propertyValuesMap = valueDOList.stream().collect(Collectors.groupingBy(ProductPropertyValueDO::getPropertyId)); - productPropertyRespVO.forEach(p -> p.setValues(ProductPropertyValueConvert.INSTANCE.convertList(propertyValuesMap.get(p.getId())))); - return productPropertyRespVO; + List valueDOList = productPropertyValueMapper.getPropertyValueListByPropertyId(CollectionUtils.convertList(propertyList, ProductPropertyRespVO::getId)); + Map> valueDOMap = valueDOList.stream() + .map(ProductPropertyValueConvert.INSTANCE::convert) + .collect(Collectors.groupingBy(ProductPropertyValueRespVO::getPropertyId)); + //组装 + return propertyList.stream().map(m -> { + ProductPropertyAndValueRespVO productPropertyAndValueRespVO = BeanUtil.copyProperties(m, ProductPropertyAndValueRespVO.class); + productPropertyAndValueRespVO.setValues(valueDOMap.get(m.getId())); + return productPropertyAndValueRespVO; + }).collect(Collectors.toList()); } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java new file mode 100644 index 000000000..4d2f27ee2 --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueService.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.product.service.property; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; + +import java.util.List; + +/** + *

+ * + *

+ * + * @author LuoWenFeng + */ +public interface ProductPropertyValueService { + + /** + * 创建规格值 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO); + + /** + * 更新规格值 + * + * @param updateReqVO 更新信息 + */ + void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO); + + /** + * 删除规格值 + * + * @param id 编号 + */ + void deletePropertyValue(Long id); + + /** + * 获得规格值 + * + * @param id 编号 + * @return 规格名称 + */ + ProductPropertyValueRespVO getPropertyValue(Long id); + + /** + * 获得规格值 + * + * @param id 编号 + * @return 规格名称 + */ + List getPropertyValueListByPropertyId(List id); + + /** + * 获取规格值 分页 + * + * @param pageReqVO 查询条件 + * @return + */ + PageResult getPropertyValueListPage(ProductPropertyValuePageReqVO pageReqVO); +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java new file mode 100644 index 000000000..e62270e8b --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyValueServiceImpl.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.product.service.property; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueCreateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValuePageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueUpdateReqVO; +import cn.iocoder.yudao.module.product.convert.propertyvalue.ProductPropertyValueConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO; +import cn.iocoder.yudao.module.product.dal.mysql.property.ProductPropertyValueMapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * + *

+ * + * @author LuoWenFeng + */ +@Service +@Validated +public class ProductPropertyValueServiceImpl implements ProductPropertyValueService { + + @Resource + private ProductPropertyValueMapper productPropertyValueMapper; + + @Override + public Long createPropertyValue(ProductPropertyValueCreateReqVO createReqVO) { + ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(createReqVO); + productPropertyValueMapper.insert(convert); + return convert.getId(); + } + + @Override + public void updatePropertyValue(ProductPropertyValueUpdateReqVO updateReqVO) { + ProductPropertyValueDO convert = ProductPropertyValueConvert.INSTANCE.convert(updateReqVO); + productPropertyValueMapper.updateById(convert); + } + + @Override + public void deletePropertyValue(Long id) { + productPropertyValueMapper.deleteById(id); + } + + @Override + public ProductPropertyValueRespVO getPropertyValue(Long id) { + ProductPropertyValueDO productPropertyValueDO = productPropertyValueMapper.selectOne(new LambdaQueryWrapper() + .eq(ProductPropertyValueDO::getId, id)); + return ProductPropertyValueConvert.INSTANCE.convert(productPropertyValueDO); + } + + @Override + public List getPropertyValueListByPropertyId(List id) { + return ProductPropertyValueConvert.INSTANCE.convertList(productPropertyValueMapper.selectList("property_id", id)); + } + + @Override + public PageResult getPropertyValueListPage(ProductPropertyValuePageReqVO pageReqVO) { + return ProductPropertyValueConvert.INSTANCE.convertPage(productPropertyValueMapper.selectPage(pageReqVO)); + } +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java index bf8dab778..96cea6171 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.product.service.sku; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper; import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -39,6 +40,9 @@ public class ProductSkuServiceImpl implements ProductSkuService { @Resource private ProductPropertyService productPropertyService; + @Resource + private ProductPropertyValueService productPropertyValueService; + @Override public void deleteSku(Long id) { // 校验存在 @@ -71,17 +75,15 @@ public class ProductSkuServiceImpl implements ProductSkuService { } // 1、校验规格属性存在 - // TODO @Luowenfeng:stream 的写法;不用改哈,就是说下可以酱紫写; Set propertyIds = skus.stream().filter(p -> p.getProperties() != null).flatMap(p -> p.getProperties().stream()) // 遍历多个 Property 属性 .map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toSet()); // 将每个 Property 转换成对应的 propertyId,最后形成集合 - List propertyAndValueList = productPropertyService.getPropertyAndValueList(propertyIds); - if (propertyAndValueList.size() == propertyIds.size()) { + List propertyList = productPropertyService.getPropertyList(propertyIds); + if (propertyList.size() != propertyIds.size()) { throw exception(PROPERTY_NOT_EXISTS); } // 2. 校验,一个 SKU 下,没有重复的规格。校验方式是,遍历每个 SKU ,看看是否有重复的规格 propertyId - Map propertyValueMap = propertyAndValueList.stream().filter(p -> p.getValues() != null).flatMap(p -> p.getValues().stream()) - .collect(Collectors.toMap(ProductPropertyValueRespVO::getId, value -> value)); // KEY:规格属性值的编号 + Map propertyValueMap = CollectionUtils.convertMap(productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(propertyIds)), ProductPropertyValueRespVO::getId); skus.forEach(sku -> { Set skuPropertyIds = CollectionUtils.convertSet(sku.getProperties(), propertyItem -> propertyValueMap.get(propertyItem.getValueId()).getPropertyId()); if (skuPropertyIds.size() != sku.getProperties().size()) { @@ -100,8 +102,7 @@ public class ProductSkuServiceImpl implements ProductSkuService { // 4. 最后校验,每个 Sku 之间不是重复的 Set> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的. for (ProductSkuCreateOrUpdateReqVO sku : skus) { - // TODO @Luowenfeng:可以使用 CollectionUtils.convertSet(),简化下面的 stream 操作 - if (!skuAttrValues.add(sku.getProperties().stream().map(ProductSkuBaseVO.Property::getValueId).collect(Collectors.toSet()))) { // 添加失败,说明重复 + if (!skuAttrValues.add(CollectionUtils.convertSet(sku.getProperties(), ProductSkuBaseVO.Property::getValueId))) { // 添加失败,说明重复 throw exception(ErrorCodeConstants.SPU_SKU_NOT_DUPLICATE); } } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java index e5affa8d2..6a12dcb52 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.product.service.spu; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; @@ -42,6 +39,14 @@ public interface ProductSpuService { */ void deleteSpu(Long id); + /** + * 获得商品spu详情 + * + * @param id 编号 + * @return 商品spu + */ + ProductSpuDetailRespVO getSpuDetail(Long id); + /** * 获得商品spu * diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 847301ba8..9fb13411b 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -1,17 +1,15 @@ package cn.iocoder.yudao.module.product.service.spu; +import cn.hutool.core.bean.BeanUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyAndValueRespVO; +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO; import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; -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.ProductSpuRespVO; -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO; import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; @@ -22,6 +20,7 @@ import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; import cn.iocoder.yudao.module.product.service.brand.ProductBrandService; import cn.iocoder.yudao.module.product.service.category.ProductCategoryService; import cn.iocoder.yudao.module.product.service.property.ProductPropertyService; +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService; import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -55,6 +54,9 @@ public class ProductSpuServiceImpl implements ProductSpuService { @Resource private ProductPropertyService productPropertyService; + @Resource + private ProductPropertyValueService productPropertyValueService; + @Resource private ProductBrandService brandService; @@ -125,28 +127,31 @@ public class ProductSpuServiceImpl implements ProductSpuService { @Override // TODO @芋艿:需要再 review 下 - public ProductSpuRespVO getSpu(Long id) { + public ProductSpuDetailRespVO getSpuDetail(Long id) { ProductSpuDO spu = ProductSpuMapper.selectById(id); - ProductSpuRespVO spuVO = ProductSpuConvert.INSTANCE.convert(spu); - if (null != spuVO) { - List skuReqs = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuId(id)); - spuVO.setSkus(skuReqs); - List properties = new ArrayList<>(); + ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class); + if (null != spu) { + List skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id)); + respVO.setSkus(skuReqs); // 组合 sku 规格属性 if(spu.getSpecType().equals(ProductSpuSpecTypeEnum.DISABLE.getType())) { - for (ProductSkuRespVO productSkuRespVO : skuReqs) { + List properties = new ArrayList<>(); + for (ProductSpuDetailRespVO.Sku productSkuRespVO : skuReqs) { properties.addAll(productSkuRespVO.getProperties()); } Map> propertyMaps = properties.stream().collect(Collectors.groupingBy(ProductSkuBaseVO.Property::getPropertyId)); - List propertyAndValueList = productPropertyService.getPropertyAndValueList(new ArrayList<>(propertyMaps.keySet())); + + List propertyValueList = productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(propertyMaps.keySet())); + List propertyList = productPropertyService.getPropertyList(new ArrayList<>(propertyMaps.keySet())); // 装载组装过后的属性 List productPropertyViews = new ArrayList<>(); - propertyAndValueList.forEach(p -> { + propertyList.forEach(p -> { ProductPropertyViewRespVO productPropertyViewRespVO = new ProductPropertyViewRespVO(); productPropertyViewRespVO.setPropertyId(p.getId()); productPropertyViewRespVO.setName(p.getName()); List propertyValues = new ArrayList<>(); - Map propertyValueMaps = p.getValues().stream().collect(Collectors.toMap(ProductPropertyValueRespVO::getId, pv -> pv)); + // 转换成map是为了能快速获取 + Map propertyValueMaps = CollectionUtils.convertMap(propertyValueList, ProductPropertyValueRespVO::getId); propertyMaps.get(p.getId()).forEach(pv -> { ProductPropertyViewRespVO.Tuple2 tuple2 = new ProductPropertyViewRespVO.Tuple2(pv.getValueId(), propertyValueMaps.get(pv.getValueId()).getName()); propertyValues.add(tuple2); @@ -154,12 +159,12 @@ public class ProductSpuServiceImpl implements ProductSpuService { productPropertyViewRespVO.setPropertyValues(propertyValues.stream().distinct().collect(Collectors.toList())); productPropertyViews.add(productPropertyViewRespVO); }); - spuVO.setProductPropertyViews(productPropertyViews); + respVO.setProductPropertyViews(productPropertyViews); } // 组合分类 - if (null != spuVO.getCategoryId()) { + if (null != respVO.getCategoryId()) { LinkedList categoryArray = new LinkedList<>(); - Long parentId = spuVO.getCategoryId(); + Long parentId = respVO.getCategoryId(); categoryArray.addFirst(parentId); while (parentId != 0) { parentId = categoryService.getCategory(parentId).getParentId(); @@ -167,10 +172,15 @@ public class ProductSpuServiceImpl implements ProductSpuService { categoryArray.addFirst(parentId); } } - spuVO.setCategoryIds(categoryArray); + respVO.setCategoryIds(categoryArray); } } - return spuVO; + return respVO; + } + + @Override + public ProductSpuRespVO getSpu(Long id) { + return ProductSpuConvert.INSTANCE.convert(ProductSpuMapper.selectById(id)); } @Override @@ -182,8 +192,8 @@ public class ProductSpuServiceImpl implements ProductSpuService { public PageResult getSpuPage(ProductSpuPageReqVO pageReqVO) { PageResult spuVOs = ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO)); // 查询 sku 的信息 - List spuIds = spuVOs.getList().stream().map(ProductSpuRespVO::getId).collect(Collectors.toList()); - List skus = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuIds(spuIds)); +// List spuIds = spuVOs.getList().stream().map(ProductSpuRespVO::getId).collect(Collectors.toList()); +// List skus = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuIds(spuIds)); // TODO @franky:使用 CollUtil 里的方法替代哈 // TODO 芋艿:临时注释 // Map> skuMap = skus.stream().collect(Collectors.groupingBy(ProductSkuRespVO::getSpuId)); diff --git a/yudao-ui-admin/src/api/mall/product/property.js b/yudao-ui-admin/src/api/mall/product/property.js index 58ae320f6..5046b9233 100644 --- a/yudao-ui-admin/src/api/mall/product/property.js +++ b/yudao-ui-admin/src/api/mall/product/property.js @@ -43,6 +43,25 @@ export function getPropertyPage(query) { }) } +// 获得规格名称列表 +export function getPropertyList(query) { + return request({ + url: '/product/property/list', + method: 'get', + params: query + }) +} + +// 获得规格名称列表 +export function getPropertyListAndValue(query) { + return request({ + url: '/product/property/listAndValue', + method: 'get', + params: query + }) +} + + // 导出规格名称 Excel export function exportPropertyExcel(query) { return request({ @@ -52,3 +71,49 @@ export function exportPropertyExcel(query) { responseType: 'blob' }) } + +// ------------------------ 规格名称值 ------------------- + +// 获得规格名称值分页 +export function getPropertyValuePage(query) { + return request({ + url: '/product/property/value/page', + method: 'get', + params: query + }) +} + +// 获得规格名称值 +export function getPropertyValue(id) { + return request({ + url: '/product/property/value/get?id=' + id, + method: 'get' + }) +} + + +// 创建规格名称值 +export function createPropertyValue(data) { + return request({ + url: '/product/property/value/create', + method: 'post', + data: data + }) +} + +// 更新规格名称值 +export function updatePropertyValue(data) { + return request({ + url: '/product/property/value/update', + method: 'put', + data: data + }) +} + +// 删除规格名称 +export function deletePropertyValue(id) { + return request({ + url: '/product/property/value/delete?id=' + id, + method: 'delete' + }) +} diff --git a/yudao-ui-admin/src/api/mall/product/spu.js b/yudao-ui-admin/src/api/mall/product/spu.js index fc4a545f2..662f1ab61 100644 --- a/yudao-ui-admin/src/api/mall/product/spu.js +++ b/yudao-ui-admin/src/api/mall/product/spu.js @@ -34,6 +34,14 @@ export function getSpu(id) { }) } +// 获得商品spu详情 +export function getSpuDetail(id) { + return request({ + url: '/product/spu/get/detail?id=' + id, + method: 'get' + }) +} + // 获得商品spu分页 export function getSpuPage(query) { return request({ diff --git a/yudao-ui-admin/src/router/index.js b/yudao-ui-admin/src/router/index.js index 7446a2f2b..3f488e5de 100644 --- a/yudao-ui-admin/src/router/index.js +++ b/yudao-ui-admin/src/router/index.js @@ -96,6 +96,17 @@ export const constantRoutes = [ meta: {title: '字典数据', icon: '', activeMenu: '/system/dict'} } ] + }, { + path: '/property', + component: Layout, + hidden: true, + children: [{ + path: 'value/:propertyId(\\d+)', + component: (resolve) => require(['@/views/mall/product/property/value'], resolve), + name: 'PropertyValue', + meta: {title: '规格数据', icon: '', activeMenu: '/mall/property'} + } + ] }, { path: '/job', component: Layout, diff --git a/yudao-ui-admin/src/views/mall/product/property/index.vue b/yudao-ui-admin/src/views/mall/product/property/index.vue index 0768ba207..36c1ab011 100644 --- a/yudao-ui-admin/src/views/mall/product/property/index.vue +++ b/yudao-ui-admin/src/views/mall/product/property/index.vue @@ -6,7 +6,7 @@ - + @@ -33,12 +33,14 @@ - - + + - + +