|
|
@@ -36,9 +36,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
@Resource
|
|
|
private ProductCategoryMapper productCategoryMapper;
|
|
|
|
|
|
- @Resource
|
|
|
- private ProductImageMapper productImageMapper;
|
|
|
-
|
|
|
@Resource
|
|
|
private ProductSpecMapper productSpecMapper;
|
|
|
|
|
|
@@ -49,7 +46,10 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
private ProductSkuMapper productSkuMapper;
|
|
|
|
|
|
/**
|
|
|
- * 新增商品(包含规格、SKU、图片)
|
|
|
+ * 新增商品
|
|
|
+ *
|
|
|
+ * @param dto 新增商品请求DTO
|
|
|
+ * @return Long 商品ID
|
|
|
*/
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
@@ -60,61 +60,52 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
throw new RuntimeException("商品分类不存在");
|
|
|
}
|
|
|
|
|
|
- // 2. 生成商品编号
|
|
|
- String productNo = generateProductNo(dto.getCategoryId());
|
|
|
-
|
|
|
- // 3. 保存商品基本信息
|
|
|
+ // 2. 保存商品基本信息
|
|
|
Product product = new Product();
|
|
|
- product.setProductNo(productNo);
|
|
|
+ product.setProductNo(dto.getProductNo());
|
|
|
product.setCategoryId(dto.getCategoryId());
|
|
|
product.setName(dto.getName());
|
|
|
product.setProductMainImage(dto.getProductMainImage());
|
|
|
product.setProductImage(dto.getProductImage());
|
|
|
product.setSummary(dto.getSummary());
|
|
|
product.setDetail(dto.getDetail());
|
|
|
- product.setPricePoint(dto.getPricePoint());
|
|
|
- product.setPriceMoney(dto.getPriceMoney());
|
|
|
- product.setStock(dto.getStock());
|
|
|
product.setFreight(dto.getFreight());
|
|
|
product.setDeliveryTime(dto.getDeliveryTime());
|
|
|
product.setServicePromise(dto.getServicePromise());
|
|
|
product.setSaleStartTime(dto.getSaleStartTime());
|
|
|
product.setSaleEndTime(dto.getSaleEndTime());
|
|
|
//product.setHasSpec(dto.getHasSpec());
|
|
|
+ // 设置付款方式
|
|
|
+ product.setPaymentType(dto.getPaymentType());
|
|
|
product.setStatus(0); // 默认下架
|
|
|
product.setSales(0); // 初始销量为0
|
|
|
product.setDeleted(0); // 未删除
|
|
|
|
|
|
// 计算总库存
|
|
|
if (!CollectionUtils.isEmpty(dto.getSkuList())) {
|
|
|
- int totalStock = dto.getSkuList().stream()
|
|
|
- .mapToInt(ProductSkuDTO::getStock)
|
|
|
- .sum();
|
|
|
+ int totalStock = dto.getSkuList().stream().mapToInt(ProductSkuDTO::getStock).sum();
|
|
|
product.setStock(totalStock);
|
|
|
}
|
|
|
|
|
|
this.save(product);
|
|
|
Long productId = product.getId();
|
|
|
|
|
|
- // 4. 保存商品副图
|
|
|
- saveProductImages(productId, dto.getProductImage());
|
|
|
-
|
|
|
- // 5. 如果有规格,保存规格和SKU
|
|
|
+ // 3. 如果有规格,保存规格和SKU
|
|
|
if (!CollectionUtils.isEmpty(dto.getSpecList())) {
|
|
|
saveProductSpecsAndSkus(productId, dto);
|
|
|
}
|
|
|
|
|
|
- log.info("商品创建成功,商品ID:{},商品编号:{}", productId, productNo);
|
|
|
+ log.info("商品创建成功,商品ID:{},商品编号:{}", productId, dto.getProductNo());
|
|
|
return productId;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 生成商品编号(公开方法,供Controller调用)
|
|
|
+ * 生成商品编号
|
|
|
* 规则:分类编码 + 当前日期(yyyyMMdd) + 序列号(3位)
|
|
|
* 示例:AD20260327001
|
|
|
*
|
|
|
* @param categoryId 分类ID
|
|
|
- * @return 生成的商品编号
|
|
|
+ * @return String 生成的商品编号
|
|
|
*/
|
|
|
@Override
|
|
|
public String generateProductNo(Long categoryId) {
|
|
|
@@ -129,13 +120,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
if (categoryCode == null || categoryCode.trim().isEmpty()) {
|
|
|
throw new RuntimeException("商品分类编码不存在");
|
|
|
}
|
|
|
-
|
|
|
// 3. 生成商品编号
|
|
|
return generateProductNoByCategoryCode(categoryCode);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 根据分类编码生成商品编号(私有方法)
|
|
|
+ * 根据分类编码生成商品编号
|
|
|
* 规则:分类编码 + 当前日期(yyyyMMdd) + 序列号(3位)
|
|
|
*
|
|
|
* @param categoryCode 分类编码
|
|
|
@@ -167,34 +157,28 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
|
|
|
/**
|
|
|
* 保存商品图片
|
|
|
+ *
|
|
|
+ * @param productId 商品ID
|
|
|
+ * @param imageUrls 图片URL列表
|
|
|
*/
|
|
|
private void saveProductImages(Long productId, List<String> imageUrls) {
|
|
|
if (CollectionUtils.isEmpty(imageUrls)) {
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- List<ProductImage> images = new ArrayList<>();
|
|
|
- for (int i = 0; i < imageUrls.size(); i++) {
|
|
|
- ProductImage image = new ProductImage();
|
|
|
- image.setProductId(productId);
|
|
|
- image.setUrl(imageUrls.get(i));
|
|
|
- image.setType(2); // 副图
|
|
|
- image.setSort(i + 1);
|
|
|
- image.setCreatedAt(LocalDateTime.now());
|
|
|
- images.add(image);
|
|
|
- }
|
|
|
- images.forEach(productImageMapper::insert);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 保存商品规格和SKU
|
|
|
+ *
|
|
|
+ * @param productId 商品ID
|
|
|
+ * @param dto 商品创建DTO
|
|
|
*/
|
|
|
private void saveProductSpecsAndSkus(Long productId, ProductCreateDTO dto) {
|
|
|
List<ProductSpecDTO> specList = dto.getSpecList();
|
|
|
List<ProductSkuDTO> skuList = dto.getSkuList();
|
|
|
|
|
|
if (CollectionUtils.isEmpty(specList) || CollectionUtils.isEmpty(skuList)) {
|
|
|
- throw new RuntimeException("规格商品必须包含规格和SKU信息");
|
|
|
+ throw new RuntimeException("商品必须包含规格和SKU信息");
|
|
|
}
|
|
|
|
|
|
// 保存规格名和规格值,并记录ID映射
|
|
|
@@ -206,7 +190,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
spec.setProductId(productId);
|
|
|
spec.setSpecName(specDTO.getSpecName());
|
|
|
spec.setSort(specDTO.getSort() != null ? specDTO.getSort() : specIndex.get() + 1);
|
|
|
- spec.setCreateTime(LocalDateTime.now());
|
|
|
productSpecMapper.insert(spec);
|
|
|
Long specId = spec.getId();
|
|
|
|
|
|
@@ -233,16 +216,14 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
sku.setProductId(productId);
|
|
|
sku.setSkuNo(generateSkuNo(productId));
|
|
|
sku.setSpecCombo(skuDTO.getSpecCombo());
|
|
|
- sku.setSpecValueIds(skuDTO.getSpecValueIndexCombo());
|
|
|
sku.setImage(skuDTO.getImage());
|
|
|
+ //sku.setSpecValueIds(skuDTO.getSpecValueIndexCombo());
|
|
|
sku.setPriceMoney(skuDTO.getPriceMoney());
|
|
|
sku.setPricePoint(skuDTO.getPricePoint());
|
|
|
sku.setOriginPrice(skuDTO.getOriginPrice());
|
|
|
sku.setStock(skuDTO.getStock());
|
|
|
sku.setSales(0);
|
|
|
sku.setStatus(1);
|
|
|
- sku.setCreatedAt(LocalDateTime.now());
|
|
|
- sku.setUpdatedAt(LocalDateTime.now());
|
|
|
productSkuMapper.insert(sku);
|
|
|
}
|
|
|
}
|
|
|
@@ -266,7 +247,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
for (ProductSpecSetupDTO.SpecItemDTO specItem : dto.getSpecList()) {
|
|
|
// 保存规格名
|
|
|
ProductSpec spec = new ProductSpec();
|
|
|
- //spec.setProductId(productId);
|
|
|
+ spec.setProductNo(dto.getProductNo());
|
|
|
// 检查规格名是否存在,如果存在,则直接通过,不插入
|
|
|
LambdaQueryWrapper<ProductSpec> specWrapper = new LambdaQueryWrapper<>();
|
|
|
specWrapper.eq(ProductSpec::getSpecName, specItem.getSpecName());
|
|
|
@@ -276,7 +257,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
}
|
|
|
spec.setSpecName(specItem.getSpecName());
|
|
|
spec.setSort(specItem.getSort() != null ? specItem.getSort() : specIndex.get() + 1);
|
|
|
- spec.setCreateTime(LocalDateTime.now());
|
|
|
productSpecMapper.insert(spec);
|
|
|
Long specId = spec.getId();
|
|
|
|
|
|
@@ -286,10 +266,9 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
for (ProductSpecSetupDTO.SpecValueItemDTO valueItem : specItem.getSpecValues()) {
|
|
|
ProductSpecValue specValue = new ProductSpecValue();
|
|
|
specValue.setSpecId(specId);
|
|
|
- //specValue.setProductId(productId);
|
|
|
+ specValue.setProductNo(dto.getProductNo());
|
|
|
specValue.setSpecValue(valueItem.getSpecValue());
|
|
|
specValue.setSort(valueItem.getSort() != null ? valueItem.getSort() : valueIndex.get() + 1);
|
|
|
- specValue.setCreateTime(LocalDateTime.now());
|
|
|
productSpecValueMapper.insert(specValue);
|
|
|
valueIndex.getAndIncrement();
|
|
|
}
|
|
|
@@ -301,23 +280,23 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
|
|
|
/**
|
|
|
* 获取商品规格组合(笛卡尔积)
|
|
|
+ * @param productId 商品ID
|
|
|
+ * @return List<SpecComboVO> 规格组合列表
|
|
|
*/
|
|
|
@Override
|
|
|
- public List<SpecComboVO> getSpecCombinations() {
|
|
|
- // 查询商品的所有规格名
|
|
|
+ public List<SpecComboVO> getSpecCombinations(String productNo) {
|
|
|
+ // 根据商品编号查询商品的所有规格名
|
|
|
LambdaQueryWrapper<ProductSpec> specWrapper = new LambdaQueryWrapper<>();
|
|
|
- //specWrapper.eq(ProductSpec::getProductId, productId).orderByAsc(ProductSpec::getSort);
|
|
|
- specWrapper.orderByAsc(ProductSpec::getSort);
|
|
|
+ specWrapper.eq(ProductSpec::getProductNo, productNo).orderByAsc(ProductSpec::getSort);
|
|
|
List<ProductSpec> specList = productSpecMapper.selectList(specWrapper);
|
|
|
|
|
|
if (CollectionUtils.isEmpty(specList)) {
|
|
|
return Collections.emptyList();
|
|
|
}
|
|
|
|
|
|
- // 查询所有规格值,按规格名分组
|
|
|
+ // 查询所有规格值
|
|
|
LambdaQueryWrapper<ProductSpecValue> valueWrapper = new LambdaQueryWrapper<>();
|
|
|
- //valueWrapper.eq(ProductSpecValue::getProductId, productId).orderByAsc(ProductSpecValue::getSort);
|
|
|
- valueWrapper.orderByAsc(ProductSpecValue::getSort);
|
|
|
+ valueWrapper.eq(ProductSpecValue::getProductNo, productNo).orderByAsc(ProductSpecValue::getSort);
|
|
|
List<ProductSpecValue> allValues = productSpecValueMapper.selectList(valueWrapper);
|
|
|
|
|
|
// 按规格名ID分组
|
|
|
@@ -356,7 +335,6 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
|
|
|
/*List<Long> specValueIds = combo.stream().map(SpecComboVO.SpecNameValue::getSpecValueId).collect(Collectors.toList());
|
|
|
vo.setSpecValueIds(specValueIds);*/
|
|
|
-
|
|
|
vo.setSpecValueText(String.join(",", specValues));
|
|
|
vo.setSpecNameValueList(combo);
|
|
|
result.add(vo);
|
|
|
@@ -366,6 +344,9 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
|
|
|
|
|
/**
|
|
|
* 计算笛卡尔积
|
|
|
+ *
|
|
|
+ * @param lists 规格值列表列表
|
|
|
+ * @return List<List<T>> 笛卡尔积结果
|
|
|
*/
|
|
|
private <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
|
|
|
if (lists.isEmpty()) {
|