Browse Source

feat(product-gift): 新增 ProductGiftService(配置保存/查询逻辑)

E2E Test Bot 2 weeks ago
parent
commit
7a558cf74b

+ 24 - 0
cfc-backend/src/main/java/com/etotem/cfc/dto/GiftConfigVO.java

@@ -0,0 +1,24 @@
+package com.etotem.cfc.dto;
+
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class GiftConfigVO {
+    private Long id;
+    private String levelCode;
+    private String levelName;
+    private Integer status;
+    private List<GiftItemVO> items;
+
+    @Data
+    public static class GiftItemVO {
+        private Long id;
+        private String giftType;
+        private Long giftProductId;
+        private String giftProductName;
+        private String giftProductImage;
+        private Integer cfValue;
+        private Integer sortOrder;
+    }
+}

+ 12 - 0
cfc-backend/src/main/java/com/etotem/cfc/dto/ProductGiftItemDTO.java

@@ -0,0 +1,12 @@
+package com.etotem.cfc.dto;
+
+import lombok.Data;
+
+@Data
+public class ProductGiftItemDTO {
+    private Long id;           // null=新增,有值=更新
+    private String giftType;   // "product" or "cf"
+    private Long giftProductId;
+    private Integer cfValue;
+    private Integer sortOrder;
+}

+ 184 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/ProductGiftService.java

@@ -0,0 +1,184 @@
+package com.etotem.cfc.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.etotem.cfc.common.Result;
+import com.etotem.cfc.dto.GiftConfigVO;
+import com.etotem.cfc.dto.ProductGiftItemDTO;
+import com.etotem.cfc.entity.MembershipLevel;
+import com.etotem.cfc.entity.Product;
+import com.etotem.cfc.entity.ProductGiftConfig;
+import com.etotem.cfc.entity.ProductGiftItem;
+import com.etotem.cfc.mapper.MembershipLevelMapper;
+import com.etotem.cfc.mapper.ProductGiftConfigMapper;
+import com.etotem.cfc.mapper.ProductGiftItemMapper;
+import com.etotem.cfc.mapper.ProductMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+@Service
+public class ProductGiftService {
+
+    @Resource
+    private ProductGiftConfigMapper configMapper;
+    @Resource
+    private ProductGiftItemMapper itemMapper;
+    @Resource
+    private ProductMapper productMapper;
+    @Resource
+    private MembershipLevelMapper levelMapper;
+
+    /** 保存赠品配置(幂等:先删后插 config + items) */
+    @Transactional
+    public Result<Void> saveGiftConfig(Long productId, String levelCode, Integer status, List<ProductGiftItemDTO> items) {
+        if (productId == null || levelCode == null || status == null) {
+            return Result.error("参数不完整");
+        }
+        // 校验等级存在且非 FREE
+        MembershipLevel level = levelMapper.selectOne(new LambdaQueryWrapper<MembershipLevel>()
+                .eq(MembershipLevel::getLevelCode, levelCode));
+        if (level == null || "FREE".equals(level.getLevelCode())) {
+            return Result.error("无效的赠送等级");
+        }
+        // 校验赠品商品(giftType=product)存在且启用
+        if (items != null) {
+            for (ProductGiftItemDTO it : items) {
+                if ("product".equals(it.getGiftType()) && it.getGiftProductId() != null) {
+                    Product giftProduct = productMapper.selectById(it.getGiftProductId());
+                    if (giftProduct == null || !"on_shelf".equals(giftProduct.getStatus())) {
+                        return Result.error("赠品商品不存在或未上架");
+                    }
+                }
+            }
+        }
+        // 先删后插(整个 config + 其下所有 items)
+        configMapper.delete(new LambdaQueryWrapper<ProductGiftConfig>()
+                .eq(ProductGiftConfig::getProductId, productId)
+                .eq(ProductGiftConfig::getLevelCode, levelCode));
+        if (status == 1) {
+            ProductGiftConfig config = new ProductGiftConfig();
+            config.setProductId(productId);
+            config.setLevelCode(levelCode);
+            config.setStatus(1);
+            config.setCreatedAt(new Date());
+            config.setUpdatedAt(new Date());
+            configMapper.insert(config);
+            if (items != null) {
+                for (ProductGiftItemDTO it : items) {
+                    ProductGiftItem item = new ProductGiftItem();
+                    item.setConfigId(config.getId());
+                    item.setGiftType(it.getGiftType());
+                    item.setGiftProductId(it.getGiftProductId());
+                    item.setCfValue(it.getCfValue() != null ? it.getCfValue() : 0);
+                    item.setSortOrder(it.getSortOrder() != null ? it.getSortOrder() : 0);
+                    // 快照商品名称和图
+                    if (it.getGiftProductId() != null) {
+                        Product gp = productMapper.selectById(it.getGiftProductId());
+                        if (gp != null) {
+                            item.setGiftProductName(gp.getName());
+                            item.setGiftProductImage(gp.getCoverImage());
+                        }
+                    }
+                    item.setCreatedAt(new Date());
+                    itemMapper.insert(item);
+                }
+            }
+        }
+        return Result.success(null);
+    }
+
+    /** 查询商品全部等级赠品配置(管理端用) */
+    public List<GiftConfigVO> listConfigsByProduct(Long productId) {
+        List<ProductGiftConfig> configs = configMapper.selectList(
+                new LambdaQueryWrapper<ProductGiftConfig>()
+                        .eq(ProductGiftConfig::getProductId, productId)
+                        .orderByAsc(ProductGiftConfig::getLevelCode));
+        return toVOList(configs);
+    }
+
+    /** 查询某商品某等级下启用的赠品配置(含库存充足校验,供商品详情展示) */
+    public List<GiftConfigVO> getActiveConfigsByProductAndLevel(Long productId, String levelCode) {
+        ProductGiftConfig config = configMapper.selectOne(new LambdaQueryWrapper<ProductGiftConfig>()
+                .eq(ProductGiftConfig::getProductId, productId)
+                .eq(ProductGiftConfig::getLevelCode, levelCode)
+                .eq(ProductGiftConfig::getStatus, 1)
+                .last("LIMIT 1"));
+        if (config == null) {
+            return Collections.emptyList();
+        }
+        List<ProductGiftItem> items = itemMapper.selectList(
+                new LambdaQueryWrapper<ProductGiftItem>()
+                        .eq(ProductGiftItem::getConfigId, config.getId())
+                        .orderByAsc(ProductGiftItem::getSortOrder));
+        GiftConfigVO vo = new GiftConfigVO();
+        vo.setId(config.getId());
+        vo.setLevelCode(config.getLevelCode());
+        MembershipLevel level = levelMapper.selectOne(new LambdaQueryWrapper<MembershipLevel>()
+                .eq(MembershipLevel::getLevelCode, levelCode));
+        vo.setLevelName(level != null ? level.getLevelName() : levelCode);
+        vo.setStatus(config.getStatus());
+        List<GiftConfigVO.GiftItemVO> itemVOs = new ArrayList<>();
+        for (ProductGiftItem it : items) {
+            GiftConfigVO.GiftItemVO itemVO = new GiftConfigVO.GiftItemVO();
+            itemVO.setId(it.getId());
+            itemVO.setGiftType(it.getGiftType());
+            itemVO.setGiftProductId(it.getGiftProductId());
+            itemVO.setGiftProductName(it.getGiftProductName());
+            itemVO.setGiftProductImage(it.getGiftProductImage());
+            itemVO.setCfValue(it.getCfValue() != null ? it.getCfValue() : 0);
+            itemVO.setSortOrder(it.getSortOrder());
+            // 库存充足校验:实物赠品必须库存>0
+            if ("product".equals(it.getGiftType()) && it.getGiftProductId() != null) {
+                Product gp = productMapper.selectById(it.getGiftProductId());
+                if (gp == null || gp.getStock() == null || gp.getStock() <= 0) {
+                    continue; // 库存不足则不展示
+                }
+            }
+            itemVOs.add(itemVO);
+        }
+        vo.setItems(itemVOs);
+        return Collections.singletonList(vo);
+    }
+
+    /** 根据 ID 查询赠品项 */
+    public ProductGiftItem getActiveItemById(Long itemId) {
+        return itemMapper.selectById(itemId);
+    }
+
+    private List<GiftConfigVO> toVOList(List<ProductGiftConfig> configs) {
+        List<GiftConfigVO> result = new ArrayList<>();
+        for (ProductGiftConfig cfg : configs) {
+            GiftConfigVO vo = new GiftConfigVO();
+            vo.setId(cfg.getId());
+            vo.setLevelCode(cfg.getLevelCode());
+            MembershipLevel level = levelMapper.selectOne(new LambdaQueryWrapper<MembershipLevel>()
+                    .eq(MembershipLevel::getLevelCode, cfg.getLevelCode()));
+            vo.setLevelName(level != null ? level.getLevelName() : cfg.getLevelCode());
+            vo.setStatus(cfg.getStatus());
+            List<ProductGiftItem> items = itemMapper.selectList(
+                    new LambdaQueryWrapper<ProductGiftItem>()
+                            .eq(ProductGiftItem::getConfigId, cfg.getId())
+                            .orderByAsc(ProductGiftItem::getSortOrder));
+            List<GiftConfigVO.GiftItemVO> itemVOs = new ArrayList<>();
+            for (ProductGiftItem it : items) {
+                GiftConfigVO.GiftItemVO itemVO = new GiftConfigVO.GiftItemVO();
+                itemVO.setId(it.getId());
+                itemVO.setGiftType(it.getGiftType());
+                itemVO.setGiftProductId(it.getGiftProductId());
+                itemVO.setGiftProductName(it.getGiftProductName());
+                itemVO.setGiftProductImage(it.getGiftProductImage());
+                itemVO.setCfValue(it.getCfValue() != null ? it.getCfValue() : 0);
+                itemVO.setSortOrder(it.getSortOrder());
+                itemVOs.add(itemVO);
+            }
+            vo.setItems(itemVOs);
+            result.add(vo);
+        }
+        return result;
+    }
+}