Commit 6d48bd1ed8651f4214b622052c5afd5269bff076

Authored by YunaiV
1 parent 544597d6

promotion:完善限时折扣的添加逻辑

Showing 16 changed files with 308 additions and 44 deletions
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java
1 package cn.iocoder.yudao.module.product.controller.admin.sku; 1 package cn.iocoder.yudao.module.product.controller.admin.sku;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO;
  7 +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
  8 +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
  9 +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
  10 +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
  11 +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
3 import io.swagger.annotations.Api; 12 import io.swagger.annotations.Api;
  13 +import io.swagger.annotations.ApiOperation;
4 import org.springframework.validation.annotation.Validated; 14 import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.GetMapping;
5 import org.springframework.web.bind.annotation.RequestMapping; 16 import org.springframework.web.bind.annotation.RequestMapping;
6 import org.springframework.web.bind.annotation.RestController; 17 import org.springframework.web.bind.annotation.RestController;
7 18
  19 +import javax.annotation.Resource;
  20 +import java.util.Collections;
  21 +import java.util.List;
  22 +import java.util.Map;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  25 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  26 +
8 @Api(tags = "管理后台 - 商品 sku") 27 @Api(tags = "管理后台 - 商品 sku")
9 @RestController 28 @RestController
10 @RequestMapping("/product/sku") 29 @RequestMapping("/product/sku")
11 @Validated 30 @Validated
12 public class ProductSkuController { 31 public class ProductSkuController {
13 32
  33 + @Resource
  34 + private ProductSkuService productSkuService;
  35 + @Resource
  36 + private ProductSpuService productSpuService;
  37 +
  38 + @GetMapping("/get-option-list")
  39 + @ApiOperation("获得商品 SKU 选项的列表")
  40 +// @PreAuthorize("@ss.hasPermission('product:sku:query')")
  41 + public CommonResult<List<ProductSkuOptionRespVO>> getSkuOptionList() {
  42 + // 获得 SKU 列表
  43 + List<ProductSkuDO> skus = productSkuService.getSkuList();
  44 + if (CollUtil.isEmpty(skus)) {
  45 + return success(Collections.emptyList());
  46 + }
  47 +
  48 + // 获得对应的 SPU 映射
  49 + Map<Long, ProductSpuDO> spuMap = productSpuService.getSpuMap(convertSet(skus, ProductSkuDO::getSpuId));
  50 + // 转换为返回结果
  51 + List<ProductSkuOptionRespVO> skuVOs = ProductSkuConvert.INSTANCE.convertList05(skus);
  52 + skuVOs.forEach(sku -> MapUtils.findAndThen(spuMap, sku.getSpuId(),
  53 + spu -> sku.setSpuId(spu.getId()).setSpuName(spu.getName())));
  54 + return success(skuVOs);
  55 + }
  56 +
14 } 57 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +@ApiModel(value = "管理后台 - 商品 SKU 选项 Response VO", description = "用于前端 SELECT 选项")
  8 +@Data
  9 +public class ProductSkuOptionRespVO {
  10 +
  11 + @ApiModelProperty(value = "主键", required = true, example = "1024")
  12 + private Long id;
  13 +
  14 + @ApiModelProperty(value = "商品 SKU 名字", example = "红色")
  15 + private String name;
  16 +
  17 + @ApiModelProperty(value = "销售价格", required = true, example = "100", notes = "单位:分")
  18 + private String price;
  19 +
  20 + @ApiModelProperty(value = "库存", required = true, example = "100")
  21 + private Integer stock;
  22 +
  23 + // ========== 商品 SPU 信息 ==========
  24 +
  25 + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1")
  26 + private Long spuId;
  27 +
  28 + @ApiModelProperty(value = "商品 SPU 名字", required = true, example = "iPhone 11")
  29 + private String spuName;
  30 +
  31 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java
@@ -9,7 +9,7 @@ import lombok.ToString; @@ -9,7 +9,7 @@ import lombok.ToString;
9 import java.util.Date; 9 import java.util.Date;
10 import java.util.List; 10 import java.util.List;
11 11
12 -@ApiModel("管理后台 - 商品sku Response VO") 12 +@ApiModel("管理后台 - 商品 SKU Response VO")
13 @Data 13 @Data
14 @EqualsAndHashCode(callSuper = true) 14 @EqualsAndHashCode(callSuper = true)
15 @ToString(callSuper = true) 15 @ToString(callSuper = true)
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.convert.sku; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.convert.sku;
2 2
3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; 4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
  5 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO;
5 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; 6 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
6 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO; 7 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO;
7 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; 8 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
@@ -11,7 +12,7 @@ import org.mapstruct.factory.Mappers; @@ -11,7 +12,7 @@ import org.mapstruct.factory.Mappers;
11 import java.util.List; 12 import java.util.List;
12 13
13 /** 14 /**
14 - * 商品sku Convert 15 + * 商品 SKU Convert
15 * 16 *
16 * @author 芋道源码 17 * @author 芋道源码
17 */ 18 */
@@ -36,4 +37,6 @@ public interface ProductSkuConvert { @@ -36,4 +37,6 @@ public interface ProductSkuConvert {
36 37
37 List<ProductSkuRespDTO> convertList04(List<ProductSkuDO> list); 38 List<ProductSkuRespDTO> convertList04(List<ProductSkuDO> list);
38 39
  40 + List<ProductSkuOptionRespVO> convertList05(List<ProductSkuDO> skus);
  41 +
39 } 42 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java
@@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO { @@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO {
97 * 商品属性 97 * 商品属性
98 */ 98 */
99 @Data 99 @Data
  100 + @NoArgsConstructor
100 @AllArgsConstructor 101 @AllArgsConstructor
101 public static class Property { 102 public static class Property {
102 103
@@ -130,19 +131,5 @@ public class ProductSkuDO extends BaseDO { @@ -130,19 +131,5 @@ public class ProductSkuDO extends BaseDO {
130 131
131 } 132 }
132 133
133 - // TODO ========== 待定字段:yv =========  
134 - // TODO brokerage:一级返佣  
135 - // TODO brokerage_two:二级返佣  
136 - // TODO pink_price:拼团价  
137 - // TODO pink_stock:拼团库存  
138 - // TODO seckill_price:秒杀价  
139 - // TODO seckill_stock:秒杀库存  
140 - // TODO integral:需要积分  
141 -  
142 - // TODO ========== 待定字段:cf =========  
143 - // TODO type 活动显示排序 0=默认 1=秒 2=砍价 3=拼团  
144 - // TODO quota 活动限购数量  
145 - // TODO quota_show 活动限购数量显示  
146 -  
147 } 134 }
148 135
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
@@ -14,22 +14,29 @@ import java.util.List; @@ -14,22 +14,29 @@ import java.util.List;
14 public interface ProductSkuService { 14 public interface ProductSkuService {
15 15
16 /** 16 /**
17 - * 删除商品sku 17 + * 删除商品 SKU
18 * 18 *
19 * @param id 编号 19 * @param id 编号
20 */ 20 */
21 void deleteSku(Long id); 21 void deleteSku(Long id);
22 22
23 /** 23 /**
24 - * 获得商品sku 24 + * 获得商品 SKU 信息
25 * 25 *
26 * @param id 编号 26 * @param id 编号
27 - * @return 商品sku 27 + * @return 商品 SKU 信息
28 */ 28 */
29 ProductSkuDO getSku(Long id); 29 ProductSkuDO getSku(Long id);
30 30
31 /** 31 /**
32 - * 获得商品sku列表 32 + * 获得商品 SKU 列表
  33 + *
  34 + * @return 商品sku列表
  35 + */
  36 + List<ProductSkuDO> getSkuList();
  37 +
  38 + /**
  39 + * 获得商品 SKU 列表
33 * 40 *
34 * @param ids 编号 41 * @param ids 编号
35 * @return 商品sku列表 42 * @return 商品sku列表
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
@@ -62,6 +62,11 @@ public class ProductSkuServiceImpl implements ProductSkuService { @@ -62,6 +62,11 @@ public class ProductSkuServiceImpl implements ProductSkuService {
62 } 62 }
63 63
64 @Override 64 @Override
  65 + public List<ProductSkuDO> getSkuList() {
  66 + return productSkuMapper.selectList();
  67 + }
  68 +
  69 + @Override
65 public List<ProductSkuDO> getSkuList(Collection<Long> ids) { 70 public List<ProductSkuDO> getSkuList(Collection<Long> ids) {
66 return productSkuMapper.selectBatchIds(ids); 71 return productSkuMapper.selectBatchIds(ids);
67 } 72 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
@@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; @@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
9 import javax.validation.Valid; 9 import javax.validation.Valid;
10 import java.util.Collection; 10 import java.util.Collection;
11 import java.util.List; 11 import java.util.List;
  12 +import java.util.Map;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
12 15
13 /** 16 /**
14 * 商品 SPU Service 接口 17 * 商品 SPU Service 接口
@@ -64,6 +67,16 @@ public interface ProductSpuService { @@ -64,6 +67,16 @@ public interface ProductSpuService {
64 List<ProductSpuDO> getSpuList(Collection<Long> ids); 67 List<ProductSpuDO> getSpuList(Collection<Long> ids);
65 68
66 /** 69 /**
  70 + * 获得商品 SPU 映射
  71 + *
  72 + * @param ids 编号数组
  73 + * @return 商品 SPU 映射
  74 + */
  75 + default Map<Long, ProductSpuDO> getSpuMap(Collection<Long> ids) {
  76 + return convertMap(getSpuList(ids), ProductSpuDO::getId);
  77 + }
  78 +
  79 + /**
67 * 获得所有商品 SPU 列表 80 * 获得所有商品 SPU 列表
68 * 81 *
69 * @return 商品 SPU 列表 82 * @return 商品 SPU 列表
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java
@@ -130,11 +130,11 @@ public class CouponTemplateBaseVO { @@ -130,11 +130,11 @@ public class CouponTemplateBaseVO {
130 || fixedEndTerm != null; 130 || fixedEndTerm != null;
131 } 131 }
132 132
133 - @AssertTrue(message = "折扣百分比需要大于等于 1") 133 + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99")
134 @JsonIgnore 134 @JsonIgnore
135 public boolean isDiscountPercentValid() { 135 public boolean isDiscountPercentValid() {
136 return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) 136 return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
137 - || (discountPercent != null && discountPercent >= 1); 137 + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99);
138 } 138 }
139 139
140 @AssertTrue(message = "优惠金额不能为空") 140 @AssertTrue(message = "优惠金额不能为空")
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java
1 package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; 1 package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import io.swagger.annotations.ApiModel; 7 import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 8 import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 9 import lombok.Data;
6 import org.springframework.format.annotation.DateTimeFormat; 10 import org.springframework.format.annotation.DateTimeFormat;
7 11
  12 +import javax.validation.constraints.AssertTrue;
8 import javax.validation.constraints.Min; 13 import javax.validation.constraints.Min;
9 import javax.validation.constraints.NotNull; 14 import javax.validation.constraints.NotNull;
10 import java.util.Date; 15 import java.util.Date;
@@ -47,10 +52,31 @@ public class DiscountActivityBaseVO { @@ -47,10 +52,31 @@ public class DiscountActivityBaseVO {
47 @NotNull(message = "商品 SKU 编号不能为空") 52 @NotNull(message = "商品 SKU 编号不能为空")
48 private Long skuId; 53 private Long skuId;
49 54
50 - @ApiModelProperty(value = "折扣价格,单位:分", required = true, example = "1000")  
51 - @NotNull(message = "折扣价格不能为空")  
52 - @Min(value = 1, message = "折扣价格必须大于 0") 55 + @ApiModelProperty(value = "优惠类型", required = true, example = "1", notes = "参见 PromotionDiscountTypeEnum 枚举")
  56 + @NotNull(message = "优惠类型不能为空")
  57 + @InEnum(PromotionDiscountTypeEnum.class)
  58 + private Integer discountType;
  59 +
  60 + @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80")
  61 + private Integer discountPercent;
  62 +
  63 + @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分")
  64 + @Min(value = 0, message = "优惠金额需要大于等于 0")
53 private Integer discountPrice; 65 private Integer discountPrice;
54 66
  67 + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99")
  68 + @JsonIgnore
  69 + public boolean isDiscountPercentValid() {
  70 + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
  71 + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99);
  72 + }
  73 +
  74 + @AssertTrue(message = "优惠金额不能为空")
  75 + @JsonIgnore
  76 + public boolean isDiscountPriceValid() {
  77 + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PRICE.getType())
  78 + || discountPrice != null;
  79 + }
  80 +
55 } 81 }
56 } 82 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java
@@ -5,7 +5,8 @@ import lombok.Data; @@ -5,7 +5,8 @@ import lombok.Data;
5 import lombok.EqualsAndHashCode; 5 import lombok.EqualsAndHashCode;
6 import lombok.ToString; 6 import lombok.ToString;
7 7
8 -import javax.validation.constraints.NotNull; 8 +import javax.validation.Valid;
  9 +import javax.validation.constraints.NotEmpty;
9 import java.util.List; 10 import java.util.List;
10 11
11 @ApiModel("管理后台 - 限时折扣活动创建 Request VO") 12 @ApiModel("管理后台 - 限时折扣活动创建 Request VO")
@@ -17,7 +18,8 @@ public class DiscountActivityCreateReqVO extends DiscountActivityBaseVO { @@ -17,7 +18,8 @@ public class DiscountActivityCreateReqVO extends DiscountActivityBaseVO {
17 /** 18 /**
18 * 商品列表 19 * 商品列表
19 */ 20 */
20 - @NotNull(message = "商品列表不能为空") 21 + @NotEmpty(message = "商品列表不能为空")
  22 + @Valid
21 private List<Product> products; 23 private List<Product> products;
22 24
23 } 25 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java
@@ -6,6 +6,8 @@ import lombok.Data; @@ -6,6 +6,8 @@ import lombok.Data;
6 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
7 import lombok.ToString; 7 import lombok.ToString;
8 8
  9 +import javax.validation.Valid;
  10 +import javax.validation.constraints.NotEmpty;
9 import javax.validation.constraints.NotNull; 11 import javax.validation.constraints.NotNull;
10 import java.util.List; 12 import java.util.List;
11 13
@@ -22,7 +24,8 @@ public class DiscountActivityUpdateReqVO extends DiscountActivityBaseVO { @@ -22,7 +24,8 @@ public class DiscountActivityUpdateReqVO extends DiscountActivityBaseVO {
22 /** 24 /**
23 * 商品列表 25 * 商品列表
24 */ 26 */
25 - @NotNull(message = "商品列表不能为空") 27 + @NotEmpty(message = "商品列表不能为空")
  28 + @Valid
26 private List<DiscountActivityCreateReqVO.Product> products; 29 private List<DiscountActivityCreateReqVO.Product> products;
27 30
28 } 31 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java
1 package cn.iocoder.yudao.module.promotion.dal.dataobject.discount; 1 package cn.iocoder.yudao.module.promotion.dal.dataobject.discount;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
4 import com.baomidou.mybatisplus.annotation.KeySequence; 5 import com.baomidou.mybatisplus.annotation.KeySequence;
5 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
@@ -41,8 +42,23 @@ public class DiscountProductDO extends BaseDO { @@ -41,8 +42,23 @@ public class DiscountProductDO extends BaseDO {
41 * 关联 ProductSkuDO 的 id 编号 42 * 关联 ProductSkuDO 的 id 编号
42 */ 43 */
43 private Long skuId; 44 private Long skuId;
  45 +
  46 + /**
  47 + * 折扣类型
  48 + *
  49 + * 枚举 {@link PromotionDiscountTypeEnum}
  50 + */
  51 + private Integer discountType;
44 /** 52 /**
45 - * 优惠价格,单位:分 53 + * 折扣百分比
  54 + *
  55 + * 例如,80% 为 80
  56 + */
  57 + private Integer discountPercent;
  58 + /**
  59 + * 优惠金额,单位:分
  60 + *
  61 + * 当 {@link #discountType} 为 {@link PromotionDiscountTypeEnum#PRICE} 生效
46 */ 62 */
47 private Integer discountPrice; 63 private Integer discountPrice;
48 64
yudao-ui-admin/src/api/mall/product/sku.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获得商品 SKU 选项的列表
  4 +export function getSkuOptionList() {
  5 + return request({
  6 + url: '/product/sku/get-option-list',
  7 + method: 'get',
  8 + })
  9 +}
yudao-ui-admin/src/api/mall/product/spu.js
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 2
3 -// 创建商品spu 3 +// 创建商品 SPU
4 export function createSpu(data) { 4 export function createSpu(data) {
5 return request({ 5 return request({
6 url: '/product/spu/create', 6 url: '/product/spu/create',
@@ -9,7 +9,7 @@ export function createSpu(data) { @@ -9,7 +9,7 @@ export function createSpu(data) {
9 }) 9 })
10 } 10 }
11 11
12 -// 更新商品spu 12 +// 更新商品 SPU
13 export function updateSpu(data) { 13 export function updateSpu(data) {
14 return request({ 14 return request({
15 url: '/product/spu/update', 15 url: '/product/spu/update',
@@ -18,7 +18,7 @@ export function updateSpu(data) { @@ -18,7 +18,7 @@ export function updateSpu(data) {
18 }) 18 })
19 } 19 }
20 20
21 -// 删除商品spu 21 +// 删除商品 SPU
22 export function deleteSpu(id) { 22 export function deleteSpu(id) {
23 return request({ 23 return request({
24 url: '/product/spu/delete?id=' + id, 24 url: '/product/spu/delete?id=' + id,
@@ -34,7 +34,7 @@ export function getSpu(id) { @@ -34,7 +34,7 @@ export function getSpu(id) {
34 }) 34 })
35 } 35 }
36 36
37 -// 获得商品spu详情 37 +// 获得商品 SPU 详情
38 export function getSpuDetail(id) { 38 export function getSpuDetail(id) {
39 return request({ 39 return request({
40 url: '/product/spu/get/detail?id=' + id, 40 url: '/product/spu/get/detail?id=' + id,
@@ -42,7 +42,7 @@ export function getSpuDetail(id) { @@ -42,7 +42,7 @@ export function getSpuDetail(id) {
42 }) 42 })
43 } 43 }
44 44
45 -// 获得商品spu分页 45 +// 获得商品 SPU 分页
46 export function getSpuPage(query) { 46 export function getSpuPage(query) {
47 return request({ 47 return request({
48 url: '/product/spu/page', 48 url: '/product/spu/page',
yudao-ui-admin/src/views/mall/promotion/discountActivity/index.vue
@@ -70,7 +70,7 @@ @@ -70,7 +70,7 @@
70 @pagination="getList"/> 70 @pagination="getList"/>
71 71
72 <!-- 对话框(添加 / 修改) --> 72 <!-- 对话框(添加 / 修改) -->
73 - <el-dialog :title="title" :visible.sync="open" width="600px" v-dialogDrag append-to-body> 73 + <el-dialog :title="title" :visible.sync="open" width="1000px" v-dialogDrag append-to-body>
74 <el-form ref="form" :model="form" :rules="rules" label-width="80px"> 74 <el-form ref="form" :model="form" :rules="rules" label-width="80px">
75 <el-form-item label="活动名称" prop="name"> 75 <el-form-item label="活动名称" prop="name">
76 <el-input v-model="form.name" placeholder="请输入活动名称" /> 76 <el-input v-model="form.name" placeholder="请输入活动名称" />
@@ -80,7 +80,54 @@ @@ -80,7 +80,54 @@
80 </el-form-item> 80 </el-form-item>
81 <el-form-item label="活动时间" prop="startAndEndTime"> 81 <el-form-item label="活动时间" prop="startAndEndTime">
82 <el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange" :default-time="['00:00:00', '23:59:59']" 82 <el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
83 - value-format="timestamp" placeholder="选择开始时间" style="width: 480px" /> 83 + value-format="timestamp" placeholder="选择开始时间" style="width: 880px" />
  84 + </el-form-item>
  85 + <el-form-item label="商品选择">
  86 + <el-select v-model="form.skuIds" placeholder="请选择活动商品" clearable size="small"
  87 + multiple filterable style="width: 400px" @change="changeFormSku">
  88 + <el-option v-for="item in productSkus" :key="item.id" :label="item.name" :value="item.id">
  89 + <span style="float: left">{{ item.spuName }} &nbsp; {{ item.name}}</span>
  90 + <span style="float: right; color: #8492a6; font-size: 13px">¥{{ (item.price / 100.0).toFixed(2) }}</span>
  91 + </el-option>
  92 + </el-select>
  93 + <el-table v-loading="loading" :data="form.products">
  94 + <el-table-column label="商品名称" align="center" width="200">
  95 + <template slot-scope="scope">
  96 + {{ scope.row.spuName }} &nbsp; {{ scope.row.name}}
  97 + </template>
  98 + </el-table-column>
  99 + <el-table-column label="商品价格" align="center" prop="price">
  100 + <template slot-scope="scope">
  101 + ¥{{ (scope.row.price / 100.0).toFixed(2) }}
  102 + </template>
  103 + </el-table-column>
  104 + <el-table-column label="库存" align="center" prop="stock" />
  105 + <el-table-column label="优惠类型" align="center">
  106 + <template slot-scope="scope">
  107 + <el-select v-model="scope.row.discountType" placeholder="请选择优惠类型">
  108 + <el-option v-for="dict in getDictDatas(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
  109 + :key="dict.value" :label="dict.label" :value="parseInt(dict.value)"/>
  110 + </el-select>
  111 + </template>
  112 + </el-table-column>
  113 + <el-table-column label="优惠" align="center" prop="startTime" width="250">
  114 + <template slot-scope="scope">
  115 + <el-form-item v-if="scope.row.discountType === PromotionDiscountTypeEnum.PRICE.type" prop="discountPrice">
  116 + 减 <el-input-number v-model="scope.row.discountPrice" placeholder="请输入优惠金额"
  117 + style="width: 190px" :precision="2" :min="0" /> 元
  118 + </el-form-item>
  119 + <el-form-item v-if="scope.row.discountType === PromotionDiscountTypeEnum.PERCENT.type" prop="discountPercent">
  120 + 打 <el-input-number v-model="scope.row.discountPercent" placeholder="请输入优惠折扣"
  121 + style="width: 190px" :precision="1" :min="1" :max="9.9" /> 折
  122 + </el-form-item>
  123 + </template>
  124 + </el-table-column>
  125 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  126 + <template slot-scope="scope">
  127 + <el-button size="mini" type="text" icon="el-icon-delete" @click="removeFormSku(scope.row.skuId)">删除</el-button>
  128 + </template>
  129 + </el-table-column>
  130 + </el-table>
84 </el-form-item> 131 </el-form-item>
85 </el-form> 132 </el-form>
86 <div slot="footer" class="dialog-footer"> 133 <div slot="footer" class="dialog-footer">
@@ -93,8 +140,11 @@ @@ -93,8 +140,11 @@
93 140
94 <script> 141 <script>
95 import { createDiscountActivity, updateDiscountActivity, deleteDiscountActivity, getDiscountActivity, getDiscountActivityPage } from "@/api/mall/promotion/discountActivity"; 142 import { createDiscountActivity, updateDiscountActivity, deleteDiscountActivity, getDiscountActivity, getDiscountActivityPage } from "@/api/mall/promotion/discountActivity";
96 -import {PromotionActivityStatusEnum, PromotionProductScopeEnum} from "@/utils/constants";  
97 -import {closeRewardActivity} from "@/api/mall/promotion/rewardActivity"; 143 +import {
  144 + PromotionActivityStatusEnum, PromotionDiscountTypeEnum,
  145 + PromotionProductScopeEnum
  146 +} from "@/utils/constants";
  147 +import { getSkuOptionList } from "@/api/mall/product/sku";
98 148
99 export default { 149 export default {
100 name: "DiscountActivity", 150 name: "DiscountActivity",
@@ -115,7 +165,7 @@ export default { @@ -115,7 +165,7 @@ export default {
115 // 弹出层名称 165 // 弹出层名称
116 title: "", 166 title: "",
117 // 是否显示弹出层 167 // 是否显示弹出层
118 - open: false, 168 + open: true,
119 // 查询参数 169 // 查询参数
120 queryParams: { 170 queryParams: {
121 pageNo: 1, 171 pageNo: 1,
@@ -125,17 +175,38 @@ export default { @@ -125,17 +175,38 @@ export default {
125 createTime: [], 175 createTime: [],
126 }, 176 },
127 // 表单参数 177 // 表单参数
128 - form: {}, 178 + form: {
  179 + skuIds: [], // 选中的 SKU
  180 + products: [], // 商品信息
  181 + // products: [{
  182 + // id: 2,
  183 + // name: '白色',
  184 + // price: 500,
  185 + // stock: 20,
  186 + // spuId: 1,
  187 + // spuName: 'iPhone 14 Pro',
  188 + // discountType: 1,
  189 + // }, {
  190 + // id: 10,
  191 + // name: '蓝色',
  192 + // price: 1000,
  193 + // stock: 100,
  194 + // spuId: 20,
  195 + // spuName: 'iPhone 14 Pro',
  196 + // discountType: 2,
  197 + // }]
  198 + },
129 // 表单校验 199 // 表单校验
130 rules: { 200 rules: {
131 name: [{ required: true, message: "活动名称不能为空", trigger: "blur" }], 201 name: [{ required: true, message: "活动名称不能为空", trigger: "blur" }],
132 startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }], 202 startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }],
133 }, 203 },
134 - // 商品列表  
135 - productSpus: [], // TODO 芋艿:需要重新写下 204 + // 商品 SKU 列表
  205 + productSkus: [],
136 // 如下的变量,主要为了 v-if 判断可以使用到 206 // 如下的变量,主要为了 v-if 判断可以使用到
137 PromotionProductScopeEnum: PromotionProductScopeEnum, 207 PromotionProductScopeEnum: PromotionProductScopeEnum,
138 PromotionActivityStatusEnum: PromotionActivityStatusEnum, 208 PromotionActivityStatusEnum: PromotionActivityStatusEnum,
  209 + PromotionDiscountTypeEnum: PromotionDiscountTypeEnum,
139 }; 210 };
140 }, 211 },
141 created() { 212 created() {
@@ -151,6 +222,10 @@ export default { @@ -151,6 +222,10 @@ export default {
151 this.total = response.data.total; 222 this.total = response.data.total;
152 this.loading = false; 223 this.loading = false;
153 }); 224 });
  225 + // 获得 SKU 商品列表
  226 + getSkuOptionList().then(response => {
  227 + this.productSkus = response.data;
  228 + });
154 }, 229 },
155 /** 取消按钮 */ 230 /** 取消按钮 */
156 cancel() { 231 cancel() {
@@ -166,6 +241,8 @@ export default { @@ -166,6 +241,8 @@ export default {
166 startTime: undefined, 241 startTime: undefined,
167 endTime: undefined, 242 endTime: undefined,
168 remark: undefined, 243 remark: undefined,
  244 + skuIds: [],
  245 + products: [],
169 }; 246 };
170 this.resetForm("form"); 247 this.resetForm("form");
171 }, 248 },
@@ -240,7 +317,49 @@ export default { @@ -240,7 +317,49 @@ export default {
240 this.getList(); 317 this.getList();
241 this.$modal.msgSuccess("关闭成功"); 318 this.$modal.msgSuccess("关闭成功");
242 }).catch(() => {}); 319 }).catch(() => {});
243 - } 320 + },
  321 + /** 当 Form 的 SKU 发生变化时 */
  322 + changeFormSku(skuIds) {
  323 + // 处理【新增】
  324 + skuIds.forEach(skuId => {
  325 + // 获得对应的 SKU 信息
  326 + const sku = this.productSkus.find(item => item.id === skuId);
  327 + if (!sku) {
  328 + // debugger
  329 + return;
  330 + }
  331 + // 判断已存在,直接跳过
  332 + const product = this.form.products.find(item => item.skuId === skuId);
  333 + if (product) {
  334 + // debugger
  335 + return;
  336 + }
  337 + this.form.products.push({
  338 + skuId: sku.id,
  339 + name: sku.name,
  340 + price: sku.price,
  341 + stock: sku.stock,
  342 + spuId: sku.spuId,
  343 + spuName: sku.spuName,
  344 + discountType: PromotionDiscountTypeEnum.PRICE.type,
  345 + });
  346 + });
  347 + // 处理【移除】
  348 + this.form.products.map((product, index) => {
  349 + if (!skuIds.includes(product.skuId)) {
  350 + this.form.products.splice(index, 1);
  351 + }
  352 + });
  353 + },
  354 + /** 移除 Form 的 SKU */
  355 + removeFormSku(skuId) {
  356 + this.form.skuIds.map((id, index) => {
  357 + if (skuId === id) {
  358 + this.form.skuIds.splice(index, 1);
  359 + }
  360 + });
  361 + this.changeFormSku(this.form.skuIds);
  362 + },
244 } 363 }
245 -}; 364 +}
246 </script> 365 </script>