From 8d269a65a5d35cfe38dd54c2b677b6e27076a19b Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Mon, 21 Nov 2022 10:57:07 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 30 +- .../liteflow/example/bean/PriceCalcReqVO.java | 69 +---- .../liteflow/example/bean/PriceStepVO.java | 84 ++---- .../liteflow/example/bean/ProductPackVO.java | 238 ++++++---------- .../liteflow/example/component/CheckCmp.java | 21 +- .../liteflow/example/component/CouponCmp.java | 35 +-- .../example/component/MemberDiscountCmp.java | 12 +- .../example/component/NodeIdConstant.java | 34 +++ .../example/component/PriceStepInitCmp.java | 60 ++-- .../component/PromotionConvertCmp.java | 80 +++--- .../example/component/SlotInitCmp.java | 25 +- .../example/component/StepPrintCmp.java | 37 +-- .../liteflow/example/enums/PriceTypeEnum.java | 78 +++-- .../liteflow/example/slot/PriceContext.java | 266 ++++++++---------- 14 files changed, 467 insertions(+), 602 deletions(-) create mode 100644 src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java diff --git a/pom.xml b/pom.xml index f2f5e22..680faef 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,8 @@ 1.8 + 2.9.3 + 2.0.19 3.4 4.1 @@ -26,6 +28,17 @@ spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + com.yomahub + liteflow-spring-boot-starter + ${liteflow.version} + + org.apache.commons commons-lang3 @@ -38,21 +51,14 @@ ${commons-collections.version} - - com.yomahub - liteflow-spring-boot-starter - 2.9.2 - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - com.alibaba fastjson - 1.2.83 + ${fastjson.version} + + + org.projectlombok + lombok diff --git a/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java b/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java index cd448b8..a99f03e 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java @@ -3,7 +3,19 @@ package com.yomahub.liteflow.example.bean; import com.yomahub.liteflow.example.enums.OrderChannelEnum; import java.util.List; - +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * 订单价格计算请求参数 + * + * @author bryan.zhang + */ + +@ToString +@Getter +@Setter public class PriceCalcReqVO { private Long id; @@ -38,59 +50,4 @@ public class PriceCalcReqVO { */ private Long couponId; - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getOrderNo() { - return orderNo; - } - - public void setOrderNo(String orderNo) { - this.orderNo = orderNo; - } - - public List getProductPackList() { - return productPackList; - } - - public void setProductPackList(List productPackList) { - this.productPackList = productPackList; - } - - public OrderChannelEnum getOrderChannel() { - return orderChannel; - } - - public void setOrderChannel(OrderChannelEnum orderChannel) { - this.orderChannel = orderChannel; - } - - public String getMemberCode() { - return memberCode; - } - - public void setMemberCode(String memberCode) { - this.memberCode = memberCode; - } - - public Long getCouponId() { - return couponId; - } - - public void setCouponId(Long couponId) { - this.couponId = couponId; - } - - public boolean isOversea() { - return oversea; - } - - public void setOversea(boolean oversea) { - this.oversea = oversea; - } } diff --git a/src/main/java/com/yomahub/liteflow/example/bean/PriceStepVO.java b/src/main/java/com/yomahub/liteflow/example/bean/PriceStepVO.java index 108c723..4455073 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/PriceStepVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/PriceStepVO.java @@ -3,93 +3,51 @@ package com.yomahub.liteflow.example.bean; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import java.math.BigDecimal; - +import lombok.Builder; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * 订单价格计算中间步骤 + * + * @author bryan.zhang + */ + +@Getter +@RequiredArgsConstructor +@ToString +@Builder public class PriceStepVO { /** * 价格类型 */ - private PriceTypeEnum priceType; + private final PriceTypeEnum priceType; /** * 价格类型关联id */ - private String extId; + private final String extId; /** * 上一步的订单总价格 */ - private BigDecimal prePrice; + private final BigDecimal prePrice; /** * 价格的变动值 */ - private BigDecimal priceChange; + private final BigDecimal priceChange; /** * 这步价格计算后的订单总价格 */ - private BigDecimal currPrice; + private final BigDecimal currPrice; /** * 价格步骤描述 */ - private String stepDesc; - - public PriceStepVO(PriceTypeEnum priceType, String extId, BigDecimal prePrice, BigDecimal priceChange, BigDecimal currPrice, String stepDesc) { - this.priceType = priceType; - this.extId = extId; - this.prePrice = prePrice; - this.priceChange = priceChange; - this.currPrice = currPrice; - this.stepDesc = stepDesc; - } - - public PriceTypeEnum getPriceType() { - return priceType; - } - - public void setPriceType(PriceTypeEnum priceType) { - this.priceType = priceType; - } - - public String getExtId() { - return extId; - } - - public void setExtId(String extId) { - this.extId = extId; - } - - public BigDecimal getPrePrice() { - return prePrice; - } - - public void setPrePrice(BigDecimal prePrice) { - this.prePrice = prePrice; - } - - public BigDecimal getPriceChange() { - return priceChange; - } - - public void setPriceChange(BigDecimal priceChange) { - this.priceChange = priceChange; - } - - public BigDecimal getCurrPrice() { - return currPrice; - } - - public void setCurrPrice(BigDecimal currPrice) { - this.currPrice = currPrice; - } - - public String getStepDesc() { - return stepDesc; - } + private final String stepDesc; - public void setStepDesc(String stepDesc) { - this.stepDesc = stepDesc; - } } diff --git a/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java b/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java index ea79c92..2a549cb 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java @@ -2,162 +2,92 @@ package com.yomahub.liteflow.example.bean; import com.yomahub.liteflow.example.enums.CategoryEnum; import com.yomahub.liteflow.example.enums.SkuSourceEnum; - import java.math.BigDecimal; import java.util.List; - +import java.util.Objects; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +/** + * 商品信息 + * + * @author bryan.zhang + */ + +@ToString +@Getter +@Setter public class ProductPackVO { - /** - * 这里注意下,product和sku的关系,一个商品可能有很多规格,比如Product是"NIKE运动鞋",SKU就是"NIKE运动鞋黑色40码" - */ - - /** - * 商品ID - */ - private Long productId; - - /** - * 商品CODE - */ - private String productCode; - - /** - * SKU ID - */ - private Long skuId; - - /** - * SKU CODE - */ - private String skuCode; - - /** - * SKU名称 - */ - private String skuName; - - /** - * 商品来源 - */ - private SkuSourceEnum skuSource; - - /** - * 类目 - */ - private CategoryEnum category; - - /** - * 售价 - */ - private BigDecimal salePrice; - - /** - * 数量 - */ - private Integer count; - - /** - * 优惠信息,一个商品可能有多个优惠信息 - */ - private List promotionList; - - public Long getProductId() { - return productId; - } - - public void setProductId(Long productId) { - this.productId = productId; - } - - public String getProductCode() { - return productCode; - } - - public void setProductCode(String productCode) { - this.productCode = productCode; - } - - public Long getSkuId() { - return skuId; - } - - public void setSkuId(Long skuId) { - this.skuId = skuId; - } - - public String getSkuCode() { - return skuCode; - } - - public void setSkuCode(String skuCode) { - this.skuCode = skuCode; - } - - public String getSkuName() { - return skuName; - } - - public void setSkuName(String skuName) { - this.skuName = skuName; - } - - public SkuSourceEnum getSkuSource() { - return skuSource; - } - - public void setSkuSource(SkuSourceEnum skuSource) { - this.skuSource = skuSource; - } - - public BigDecimal getSalePrice() { - return salePrice; - } - - public void setSalePrice(BigDecimal salePrice) { - this.salePrice = salePrice; - } - - public Integer getCount() { - return count; - } - - public void setCount(Integer count) { - this.count = count; - } - - public CategoryEnum getCategory() { - return category; - } - - public void setCategory(CategoryEnum category) { - this.category = category; - } - - public List getPromotionList() { - return promotionList; - } - - public void setPromotionList(List promotionList) { - this.promotionList = promotionList; - } - - @Override - public boolean equals(Object obj) { - if (obj == null){ - return false; - }else{ - if(getClass() != obj.getClass()){ - return false; - }else{ - if(((ProductPackVO)obj).getSkuId().equals(this.getSkuId())){ - return true; - }else{ - return false; - } - } - } - } - - + /* + * 这里注意下,product和sku的关系,一个商品可能有很多规格,比如Product是"NIKE运动鞋",SKU就是"NIKE运动鞋黑色40码" + */ + + /** + * 商品ID + */ + private Long productId; + + /** + * 商品CODE + */ + private String productCode; + + /** + * SKU ID + */ + private Long skuId; + + /** + * SKU CODE + */ + private String skuCode; + + /** + * SKU名称 + */ + private String skuName; + + /** + * 商品来源 + */ + private SkuSourceEnum skuSource; + + /** + * 类目 + */ + private CategoryEnum category; + + /** + * 售价 + */ + private BigDecimal salePrice; + + /** + * 数量 + */ + private Integer count; + + /** + * 优惠信息,一个商品可能有多个优惠信息 + */ + private List promotionList; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ProductPackVO that = (ProductPackVO) o; + return Objects.equals(skuId, that.skuId); + } + + @Override + public int hashCode() { + return Objects.hash(skuId); + } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/CheckCmp.java b/src/main/java/com/yomahub/liteflow/example/component/CheckCmp.java index a3d287f..81c3677 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/CheckCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/CheckCmp.java @@ -1,25 +1,28 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.CHECK_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceCalcReqVO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; +import lombok.extern.slf4j.Slf4j; /** * 初始化参数检查组件 + * + * @author bryan.zhang */ -@Component("checkCmp") +@LiteflowComponent(id = CHECK_CMP, name = "初始化参数检查组件") +@Slf4j public class CheckCmp extends NodeComponent { - private Logger log = LoggerFactory.getLogger(getClass()); - @Override - public void process() throws Exception { - //拿到请求参数 + public void process() { + // 拿到请求参数 PriceCalcReqVO req = this.getSlot().getRequestData(); + log.info("请求参数:{}", req); - /***这里Mock参数验证过程***/ + // 这里Mock参数验证过程 log.info("参数验证完成"); } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/CouponCmp.java b/src/main/java/com/yomahub/liteflow/example/component/CouponCmp.java index dfe897b..d20cb89 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/CouponCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/CouponCmp.java @@ -1,44 +1,47 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.COUPON_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import com.yomahub.liteflow.example.slot.PriceContext; -import org.springframework.stereotype.Component; import java.math.BigDecimal; /** * 优惠券抵扣计算组件 + * + * @author bryan.zhang */ -@Component("couponCmp") +@LiteflowComponent(id = COUPON_CMP, name = "优惠券抵扣计算组件") public class CouponCmp extends NodeComponent { @Override - public void process() throws Exception { + public void process() { PriceContext context = this.getContextBean(PriceContext.class); - /**这里Mock下根据couponId取到的优惠卷面值为15元**/ + // 这里Mock下根据couponId取到的优惠卷面值为15元 Long couponId = context.getCouponId(); - BigDecimal couponPrice = new BigDecimal(15); + BigDecimal couponPrice = BigDecimal.valueOf(15); BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); BigDecimal currPrice = prePrice.subtract(couponPrice); - context.addPriceStep(new PriceStepVO(PriceTypeEnum.COUPON_DISCOUNT, - couponId.toString(), - prePrice, - currPrice.subtract(prePrice), - currPrice, - PriceTypeEnum.COUPON_DISCOUNT.getName())); + context.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.COUPON_DISCOUNT) + .extId(couponId.toString()) + .prePrice(prePrice) + .priceChange(couponPrice) + .currPrice(currPrice) + .stepDesc(PriceTypeEnum.COUPON_DISCOUNT.getName()) + .build()); } @Override public boolean isAccess() { PriceContext context = this.getContextBean(PriceContext.class); - if(context.getCouponId() != null){ - return true; - }else{ - return false; - } + // 是否提供了优惠券 + return context.getCouponId() != null; } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java b/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java index 2bcdbe8..d78c174 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java @@ -13,6 +13,8 @@ import java.math.RoundingMode; /** * 会员折扣计算组件 + * + * @author bryan.zhang */ @Component("memberDiscountCmp") public class MemberDiscountCmp extends NodeComponent { @@ -21,7 +23,7 @@ public class MemberDiscountCmp extends NodeComponent { PriceContext context = this.getContextBean(PriceContext.class); String memberCode = context.getMemberCode(); - /***这里Mock下通过memberCode去查会员等级表然后获取的会员折扣为9折的代码***/ + // 这里Mock下通过memberCode去查会员等级表然后获取的会员折扣为9折的代码 BigDecimal memberDiscount = new BigDecimal("0.9"); //进行计算会员折扣 @@ -41,11 +43,7 @@ public class MemberDiscountCmp extends NodeComponent { @Override public boolean isAccess() { PriceContext context = this.getContextBean(PriceContext.class); - if(CollectionUtils.isNotEmpty(context.getProductPackList()) - && StringUtils.isNotBlank(context.getMemberCode())){ - return true; - }else{ - return false; - } + return CollectionUtils.isNotEmpty(context.getProductPackList()) + && StringUtils.isNotBlank(context.getMemberCode()); } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java b/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java new file mode 100644 index 0000000..10f8dae --- /dev/null +++ b/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java @@ -0,0 +1,34 @@ +package com.yomahub.liteflow.example.component; + +/** + * 流程组件Id常量声明 + * + * @author 李小平 + */ +public interface NodeIdConstant { + /** + * 初始化参数检查组件Id + */ + String CHECK_CMP = "checkCmp"; + + /** + * Slot初始化组件Id + */ + String SLOT_INIT_CMP = "slotInitCmp"; + + /** + * 优惠信息转换组件 + */ + String PROMOTION_CONVERT_CMP = "promotionConvertCmp"; + + /** + * 优惠券抵扣计算组件Id + */ + String COUPON_CMP = "couponCmp"; + + + /** + * 步骤日志生成组件Id + */ + String STEP_PRINT_CMP = "stepPrintCmp"; +} diff --git a/src/main/java/com/yomahub/liteflow/example/component/PriceStepInitCmp.java b/src/main/java/com/yomahub/liteflow/example/component/PriceStepInitCmp.java index b581043..93cbf66 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/PriceStepInitCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/PriceStepInitCmp.java @@ -1,47 +1,43 @@ package com.yomahub.liteflow.example.component; +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; -import com.yomahub.liteflow.example.bean.ProductPackVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import com.yomahub.liteflow.example.slot.PriceContext; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Component; - import java.math.BigDecimal; -import java.util.List; + +import org.apache.commons.collections4.CollectionUtils; /** * 价格步骤初始化器(把原价初始化进去) + * + * @author bryan.zhang */ -@Component("priceStepInitCmp") +@LiteflowComponent(id = "priceStepInitCmp", name = "价格步骤初始化器") public class PriceStepInitCmp extends NodeComponent { - @Override - public void process() throws Exception { - PriceContext context = this.getContextBean(PriceContext.class); - //初始化价格步骤 - List packList = context.getProductPackList(); - BigDecimal totalOriginalPrice = new BigDecimal(0); - for(ProductPackVO packItem : packList){ - totalOriginalPrice = totalOriginalPrice.add(packItem.getSalePrice().multiply(new BigDecimal(packItem.getCount()))); - } - context.addPriceStep(new PriceStepVO(PriceTypeEnum.ORIGINAL, - null, - null, - totalOriginalPrice, - totalOriginalPrice, - PriceTypeEnum.ORIGINAL.getName())); - context.setOriginalOrderPrice(totalOriginalPrice); - } + @Override + public void process() throws Exception { + PriceContext context = this.getContextBean(PriceContext.class); + + // 初始化价格步骤 + BigDecimal totalOriginalPrice = context.calculateTotalOriginalPrice(); + + context.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.ORIGINAL) + .extId(null) + .prePrice(null) + .priceChange(totalOriginalPrice) + .currPrice(totalOriginalPrice) + .stepDesc(PriceTypeEnum.ORIGINAL.getName()) + .build()); + context.setOriginalOrderPrice(totalOriginalPrice); + } - @Override - public boolean isAccess() { - PriceContext context = this.getContextBean(PriceContext.class); - if(CollectionUtils.isNotEmpty(context.getProductPackList())){ - return true; - }else{ - return false; - } - } + @Override + public boolean isAccess() { + PriceContext context = this.getContextBean(PriceContext.class); + return CollectionUtils.isNotEmpty(context.getProductPackList()); + } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java b/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java index ac3693e..fad118d 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java @@ -1,61 +1,59 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.PROMOTION_CONVERT_CMP; + import cn.hutool.core.collection.ListUtil; +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.ProductPackVO; import com.yomahub.liteflow.example.bean.PromotionInfoVO; import com.yomahub.liteflow.example.bean.PromotionPackVO; import com.yomahub.liteflow.example.slot.PriceContext; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.beans.BeanUtils; -import org.springframework.stereotype.Component; - import java.util.ArrayList; import java.util.List; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.BeanUtils; /** * 把商品包的优惠信息转换成以优惠信息为主要维度的对象,以便于后面优惠信息的计算 + * + * @author bryan.zhang */ -@Component("promotionConvertCmp") +@LiteflowComponent(id = PROMOTION_CONVERT_CMP, name = "优惠信息转换组件") public class PromotionConvertCmp extends NodeComponent { - @Override - public void process() throws Exception { - PriceContext context = this.getContextBean(PriceContext.class); - List promotionPackList = new ArrayList<>(); - PromotionPackVO promotionPack = null; - for(ProductPackVO pack : context.getProductPackList()){ - if(CollectionUtils.isEmpty(pack.getPromotionList())){ - continue; - } - for(PromotionInfoVO promotion : pack.getPromotionList()){ - promotionPack = new PromotionPackVO(); - promotionPack.setId(promotion.getId()); - if(promotionPackList.contains(promotionPack)){ - promotionPack = promotionPackList.get(promotionPackList.indexOf(promotionPack)); - if(promotionPack.getRelatedProductPackList().contains(pack)){ - continue; - }else{ - promotionPack.getRelatedProductPackList().add(pack); - } - }else{ - BeanUtils.copyProperties(promotion,promotionPack); - promotionPack.setRelatedProductPackList(ListUtil.toList(pack)); - promotionPackList.add(promotionPack); - } - } - } - context.setPromotionPackList(promotionPackList); - } + @Override + public void process() throws Exception { + PriceContext context = this.getContextBean(PriceContext.class); + List promotionPackList = new ArrayList<>(); - @Override - public boolean isAccess() { - PriceContext context = this.getContextBean(PriceContext.class); - if(CollectionUtils.isNotEmpty(context.getProductPackList())){ - return true; - }else{ - return false; - } + PromotionPackVO promotionPack; + for (ProductPackVO pack : context.getProductPackList()) { + if (CollectionUtils.isEmpty(pack.getPromotionList())) { + continue; + } + for (PromotionInfoVO promotion : pack.getPromotionList()) { + promotionPack = new PromotionPackVO(); + promotionPack.setId(promotion.getId()); + if (promotionPackList.contains(promotionPack)) { + promotionPack = promotionPackList.get(promotionPackList.indexOf(promotionPack)); + if (!promotionPack.getRelatedProductPackList().contains(pack)) { + promotionPack.getRelatedProductPackList().add(pack); + } + } else { + BeanUtils.copyProperties(promotion, promotionPack); + promotionPack.setRelatedProductPackList(ListUtil.toList(pack)); + promotionPackList.add(promotionPack); + } + } } + context.setPromotionPackList(promotionPackList); + } + + @Override + public boolean isAccess() { + PriceContext context = this.getContextBean(PriceContext.class); + return CollectionUtils.isNotEmpty(context.getProductPackList()); + } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/SlotInitCmp.java b/src/main/java/com/yomahub/liteflow/example/component/SlotInitCmp.java index a26029a..43d287c 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/SlotInitCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/SlotInitCmp.java @@ -1,35 +1,30 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.SLOT_INIT_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceCalcReqVO; import com.yomahub.liteflow.example.slot.PriceContext; -import org.springframework.stereotype.Component; /** * Slot初始化组件 + * + * @author bryan.zhang */ -@Component("slotInitCmp") +@LiteflowComponent(id = SLOT_INIT_CMP, name = "Slot初始化组件") public class SlotInitCmp extends NodeComponent { @Override - public void process() throws Exception { - //把主要参数冗余到slot里 + public void process() { + // 把主要参数冗余到slot里 PriceCalcReqVO req = this.getRequestData(); PriceContext context = this.getContextBean(PriceContext.class); - context.setOrderNo(req.getOrderNo()); - context.setOversea(req.isOversea()); - context.setMemberCode(req.getMemberCode()); - context.setOrderChannel(req.getOrderChannel()); - context.setProductPackList(req.getProductPackList()); - context.setCouponId(req.getCouponId()); + context.copy(req); } @Override public boolean isAccess() { PriceCalcReqVO req = this.getSlot().getRequestData(); - if(req != null){ - return true; - }else{ - return false; - } + return req != null; } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/StepPrintCmp.java b/src/main/java/com/yomahub/liteflow/example/component/StepPrintCmp.java index ad7983d..177dc77 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/StepPrintCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/StepPrintCmp.java @@ -1,34 +1,39 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.STEP_PRINT_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.bean.ProductPackVO; import com.yomahub.liteflow.example.slot.PriceContext; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import java.math.BigDecimal; import java.math.RoundingMode; import java.text.MessageFormat; /** * 步骤日志生成组件 + * + * @author bryan.zhang */ -@Component("stepPrintCmp") +@LiteflowComponent(id = STEP_PRINT_CMP, name = "步骤日志生成组件") +@Slf4j public class StepPrintCmp extends NodeComponent { - private Logger log = LoggerFactory.getLogger(getClass()); + + private static final String LOG_SEPARATOR_LINE = "|====================================================================\n"; @Override public void process() throws Exception { PriceContext context = this.getContextBean(PriceContext.class); + StringBuilder logStr = new StringBuilder(); logStr.append(MessageFormat.format("订单号[{0}]的价格计算的明细结果:\n", context.getOrderNo())); - logStr.append("|====================================================================\n"); - for(ProductPackVO pack : context.getProductPackList()){ + logStr.append(LOG_SEPARATOR_LINE); + for (ProductPackVO pack : context.getProductPackList()){ logStr.append(MessageFormat.format("| {0} [{1}] [{2}] {3} X {4}\n", pack.getSkuName(), pack.getProductCode(), @@ -37,12 +42,14 @@ public class StepPrintCmp extends NodeComponent { pack.getCount())); } - logStr.append("|====================================================================\n"); + logStr.append(LOG_SEPARATOR_LINE); for(PriceStepVO step : context.getPriceStepList()){ - logStr.append(MessageFormat.format("| [{0} : {1}]\n",step.getStepDesc(),step.getPriceChange().setScale(2, BigDecimal.ROUND_HALF_UP).toString())); + logStr.append(MessageFormat.format("| [{0} : {1}]\n",step.getStepDesc(), + step.getPriceChange().setScale(2, RoundingMode.HALF_UP).toString())); } - logStr.append(MessageFormat.format("| [最终价 : {0}]\n",context.getFinalOrderPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString())); - logStr.append("|====================================================================\n"); + logStr.append(MessageFormat.format("| [最终价 : {0}]\n",context.getFinalOrderPrice().setScale(2, + RoundingMode.HALF_UP).toString())); + logStr.append(LOG_SEPARATOR_LINE); log.info(logStr.toString()); context.setPrintLog(logStr.toString()); } @@ -50,11 +57,7 @@ public class StepPrintCmp extends NodeComponent { @Override public boolean isAccess() { PriceContext context = this.getContextBean(PriceContext.class); - if(CollectionUtils.isNotEmpty(context.getPriceStepList())){ - return true; - }else{ - return false; - } + return CollectionUtils.isNotEmpty(context.getPriceStepList()); } } diff --git a/src/main/java/com/yomahub/liteflow/example/enums/PriceTypeEnum.java b/src/main/java/com/yomahub/liteflow/example/enums/PriceTypeEnum.java index 82e8caa..9e72369 100644 --- a/src/main/java/com/yomahub/liteflow/example/enums/PriceTypeEnum.java +++ b/src/main/java/com/yomahub/liteflow/example/enums/PriceTypeEnum.java @@ -1,28 +1,58 @@ package com.yomahub.liteflow.example.enums; +import lombok.Getter; + +/** + * 订单价格类型 + * + * @author bryan.zhang + */ + public enum PriceTypeEnum { - ORIGINAL(0, "原始价格"), - MEMBER_DISCOUNT(1, "会员折扣"), - PROMOTION_DISCOUNT(2, "促销优惠"), - COUPON_DISCOUNT(3, "优惠券抵扣"), - POSTAGE(4, "国内运费"), - OVERSEAS_POSTAGE(5, "海淘运费"), - POSTAGE_FREE(6, "实付99元免运费"); - - private Integer code; - - private String name; - - PriceTypeEnum(Integer code, String name) { - this.code = code; - this.name = name; - } - - public Integer getCode() { - return code; - } - - public String getName(){ - return name; - } + /** + * 原始价格 + */ + ORIGINAL(0, "原始价格"), + + /** + * 会员折扣 + */ + MEMBER_DISCOUNT(1, "会员折扣"), + + /** + * 促销优惠 + */ + PROMOTION_DISCOUNT(2, "促销优惠"), + + /** + * 优惠券抵扣 + */ + COUPON_DISCOUNT(3, "优惠券抵扣"), + + /** + * 国内运费 + */ + POSTAGE(4, "国内运费"), + + /** + * 海淘运费 + */ + OVERSEAS_POSTAGE(5, "海淘运费"), + + /** + * 实付99元免运费 + */ + POSTAGE_FREE(6, "实付99元免运费"); + + @Getter + private final Integer code; + + @Getter + private final String name; + + PriceTypeEnum(Integer code, String name) { + this.code = code; + this.name = name; + } + } diff --git a/src/main/java/com/yomahub/liteflow/example/slot/PriceContext.java b/src/main/java/com/yomahub/liteflow/example/slot/PriceContext.java index d74f762..bfacebc 100644 --- a/src/main/java/com/yomahub/liteflow/example/slot/PriceContext.java +++ b/src/main/java/com/yomahub/liteflow/example/slot/PriceContext.java @@ -1,169 +1,123 @@ package com.yomahub.liteflow.example.slot; +import com.yomahub.liteflow.example.bean.PriceCalcReqVO; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.bean.ProductPackVO; import com.yomahub.liteflow.example.bean.PromotionPackVO; import com.yomahub.liteflow.example.enums.OrderChannelEnum; -import org.apache.commons.collections4.CollectionUtils; - import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.collections4.CollectionUtils; +/** + * 订单价格上下文 + * + * @author bryan.zhang + */ +@Getter +@Setter public class PriceContext { - /** - * 订单号 - */ - private String orderNo; - - /** - * 是否境外购 - */ - private boolean oversea; - - /** - * 商品包 - */ - private List productPackList; - - /** - * 订单渠道 - */ - private OrderChannelEnum orderChannel; - - /** - * 会员CODE - */ - private String memberCode; - - /** - * 优惠券 - */ - private Long couponId; - - /** - * 优惠信息 - */ - private List promotionPackList; - - /** - * 价格步骤 - */ - private List priceStepList = new ArrayList<>(); - - /** - * 订单原始价格 - */ - private BigDecimal originalOrderPrice; - - /** - * 订单最终价格 - */ - private BigDecimal finalOrderPrice; - - /** - * 步骤日志 - */ - private String printLog; - - public PriceStepVO getLastestPriceStep(){ - if(CollectionUtils.isEmpty(priceStepList)){ - return null; - }else{ - return priceStepList.get(priceStepList.size()-1); - } - } - - public String getOrderNo() { - return orderNo; - } - - public void setOrderNo(String orderNo) { - this.orderNo = orderNo; - } - - public List getProductPackList() { - return productPackList; - } - - public void setProductPackList(List productPackList) { - this.productPackList = productPackList; - } - - public OrderChannelEnum getOrderChannel() { - return orderChannel; - } - - public void setOrderChannel(OrderChannelEnum orderChannel) { - this.orderChannel = orderChannel; - } - - public String getMemberCode() { - return memberCode; - } - - public void setMemberCode(String memberCode) { - this.memberCode = memberCode; - } - - public Long getCouponId() { - return couponId; - } - - public void setCouponId(Long couponId) { - this.couponId = couponId; - } - - public List getPriceStepList() { - return priceStepList; - } - - public void setPriceStepList(List priceStepList) { - this.priceStepList = priceStepList; - } - - public void addPriceStep(PriceStepVO step){ - this.priceStepList.add(step); - } - - public List getPromotionPackList() { - return promotionPackList; - } - - public void setPromotionPackList(List promotionPackList) { - this.promotionPackList = promotionPackList; - } - - public boolean isOversea() { - return oversea; - } - - public void setOversea(boolean oversea) { - this.oversea = oversea; - } - - public BigDecimal getFinalOrderPrice() { - return finalOrderPrice; - } - - public void setFinalOrderPrice(BigDecimal finalOrderPrice) { - this.finalOrderPrice = finalOrderPrice; - } - - public BigDecimal getOriginalOrderPrice() { - return originalOrderPrice; - } - - public void setOriginalOrderPrice(BigDecimal originalOrderPrice) { - this.originalOrderPrice = originalOrderPrice; - } - - public String getPrintLog() { - return printLog; - } - - public void setPrintLog(String printLog) { - this.printLog = printLog; - } + /** + * 订单号 + */ + private String orderNo; + + /** + * 是否境外购 + */ + private boolean oversea; + + /** + * 商品包 + */ + private List productPackList; + + /** + * 订单渠道 + */ + private OrderChannelEnum orderChannel; + + /** + * 会员CODE + */ + private String memberCode; + + /** + * 优惠券 + */ + private Long couponId; + + /** + * 优惠信息 + */ + private List promotionPackList; + + /** + * 价格步骤 + */ + private final List priceStepList = new ArrayList<>(); + + /** + * 订单原始价格 + */ + private BigDecimal originalOrderPrice; + + /** + * 订单最终价格 + */ + private BigDecimal finalOrderPrice; + + /** + * 步骤日志 + */ + private String printLog; + + public PriceStepVO getLastestPriceStep() { + if (CollectionUtils.isEmpty(priceStepList)) { + return null; + } else { + return priceStepList.get(priceStepList.size() - 1); + } + } + + /** + * 新增订单价格计算中间步骤 + * + * @param step 订单价格计算中间步骤 + */ + public void addPriceStep(PriceStepVO step) { + this.priceStepList.add(step); + } + + /** + * 把主要参数冗余到slot里 + * + * @param req 订单价格计算请求参数 + */ + public void copy(PriceCalcReqVO req) { + this.setOrderNo(req.getOrderNo()); + this.setOversea(req.isOversea()); + this.setMemberCode(req.getMemberCode()); + this.setOrderChannel(req.getOrderChannel()); + this.setProductPackList(req.getProductPackList()); + this.setCouponId(req.getCouponId()); + } + + /** + * 计算订单原始价格 + * + * @return 订单原始价格 + */ + public BigDecimal calculateTotalOriginalPrice() { + BigDecimal totalOriginalPrice = BigDecimal.ZERO; + for (ProductPackVO packItem : this.getProductPackList()) { + totalOriginalPrice = totalOriginalPrice.add( + packItem.getSalePrice().multiply(BigDecimal.valueOf(packItem.getCount()))); + } + return totalOriginalPrice; + } } -- Gitee From a5c376458c3fbeeab2e567b2a0498903e16c50ab Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Mon, 21 Nov 2022 17:54:02 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/bean/PromotionInfoVO.java | 70 +++++------ .../example/bean/PromotionPackVO.java | 43 +++---- .../example/component/FullCutCmp.java | 108 ++++++++--------- .../example/component/FullDiscountCmp.java | 109 +++++++++--------- .../example/component/MemberDiscountCmp.java | 32 ++--- .../example/component/NodeIdConstant.java | 27 ++++- .../component/PromotionConvertCmp.java | 15 ++- .../example/component/RushBuyCmp.java | 2 +- .../example/enums/PromotionTypeEnum.java | 25 +++- 9 files changed, 225 insertions(+), 206 deletions(-) diff --git a/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java b/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java index bb419a0..261eca6 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java @@ -1,7 +1,20 @@ package com.yomahub.liteflow.example.bean; import com.yomahub.liteflow.example.enums.PromotionTypeEnum; - +import java.util.Objects; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 优惠信息 + * + * @author bryan.zhang + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor public class PromotionInfoVO { /** @@ -24,45 +37,20 @@ public class PromotionInfoVO { */ private PromotionTypeEnum promotionType; - public PromotionInfoVO() { - } - - public PromotionInfoVO(Long id, String promotionCode, String promotionName, PromotionTypeEnum promotionType) { - this.id = id; - this.promotionCode = promotionCode; - this.promotionName = promotionName; - this.promotionType = promotionType; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getPromotionCode() { - return promotionCode; - } - - public void setPromotionCode(String promotionCode) { - this.promotionCode = promotionCode; - } - - public String getPromotionName() { - return promotionName; - } - - public void setPromotionName(String promotionName) { - this.promotionName = promotionName; - } - - public PromotionTypeEnum getPromotionType() { - return promotionType; - } - - public void setPromotionType(PromotionTypeEnum promotionType) { - this.promotionType = promotionType; + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PromotionInfoVO that = (PromotionInfoVO) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); } } diff --git a/src/main/java/com/yomahub/liteflow/example/bean/PromotionPackVO.java b/src/main/java/com/yomahub/liteflow/example/bean/PromotionPackVO.java index b598361..24bf976 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/PromotionPackVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/PromotionPackVO.java @@ -1,40 +1,23 @@ package com.yomahub.liteflow.example.bean; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import java.util.List; +import java.util.HashSet; +import java.util.Set; +import lombok.Getter; +import lombok.ToString; -public class PromotionPackVO extends PromotionInfoVO{ +/** + * 优惠包信息 + * + * @author bryan.zhang + */ +@ToString(callSuper = true) +public class PromotionPackVO extends PromotionInfoVO { /** * 这个优惠活动关联的商品包 */ - private List relatedProductPackList; - - public List getRelatedProductPackList() { - return relatedProductPackList; - } - - public void setRelatedProductPackList(List relatedProductPackList) { - this.relatedProductPackList = relatedProductPackList; - } - - @Override - public boolean equals(Object obj) { - if (obj == null){ - return false; - }else{ - if(getClass() != obj.getClass()){ - return false; - }else{ - if(((PromotionPackVO)obj).getId().equals(this.getId())){ - return true; - }else{ - return false; - } - } - } - } + @Getter + private final Set relatedProductPackSet = new HashSet<>(); } diff --git a/src/main/java/com/yomahub/liteflow/example/component/FullCutCmp.java b/src/main/java/com/yomahub/liteflow/example/component/FullCutCmp.java index 2d77bc7..8a3c7aa 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/FullCutCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/FullCutCmp.java @@ -1,5 +1,8 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.FULL_CUT_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.bean.ProductPackVO; @@ -7,72 +10,73 @@ import com.yomahub.liteflow.example.bean.PromotionPackVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import com.yomahub.liteflow.example.enums.PromotionTypeEnum; import com.yomahub.liteflow.example.slot.PriceContext; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Component; - import java.math.BigDecimal; -import java.util.List; -import java.util.stream.Collectors; +import java.util.Objects; +import java.util.Optional; + /** * 满减计算组件 + * + * @author bryan.zhang */ -@Component("fullCutCmp") +@LiteflowComponent(id = FULL_CUT_CMP, name = "满减计算组件") public class FullCutCmp extends NodeComponent { - @Override - public void process() throws Exception { - PriceContext slot = this.getContextBean(PriceContext.class); - PromotionPackVO promotionPack = getMatchPromotion(); - /***这里Mock下根据优惠信息查到的满减信息为:满100,减5块***/ - BigDecimal triggerPrice = new BigDecimal(100); - BigDecimal cutPrice = new BigDecimal(5); + /** + * 满减-优惠包 + */ + private PromotionPackVO promotionPack; + + @Override + public void process() throws Exception { + if (Objects.isNull(promotionPack)) { + return; + } - //从PromotionPack对象中取到这个优惠关联的商品信息,判断是否超过了触发满减的金额 - BigDecimal reletedProductTotalPrice = new BigDecimal(0); - for(ProductPackVO productPack : promotionPack.getRelatedProductPackList()){ - reletedProductTotalPrice = reletedProductTotalPrice.add(productPack.getSalePrice().multiply(new BigDecimal(productPack.getCount()))); - } - if (reletedProductTotalPrice.compareTo(triggerPrice) >= 0){ - BigDecimal prePrice = slot.getLastestPriceStep().getCurrPrice(); - BigDecimal currPrice = prePrice.subtract(cutPrice); + PriceContext slot = this.getContextBean(PriceContext.class); - slot.addPriceStep(new PriceStepVO(PriceTypeEnum.PROMOTION_DISCOUNT, - promotionPack.getId().toString(), - prePrice, - currPrice.subtract(prePrice), - currPrice, - PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[满减]")); - } + // 这里Mock下根据优惠信息查到的满减信息为:满100,减5块 + BigDecimal triggerPrice = BigDecimal.valueOf(100); + BigDecimal cutPrice = BigDecimal.valueOf(5); + // 从PromotionPack对象中取到这个优惠关联的商品信息,判断是否超过了触发满减的金额 + BigDecimal reletedProductTotalPrice = BigDecimal.ZERO; + for (ProductPackVO productPack : promotionPack.getRelatedProductPackSet()) { + reletedProductTotalPrice = reletedProductTotalPrice.add(productPack.getSalePrice() + .multiply(BigDecimal.valueOf(productPack.getCount()))); } - @Override - public boolean isAccess() { - //过滤出优惠信息列表中有没有满减这个活动,如果有,则进入这个组件,反义就不进入 - PromotionPackVO promotionPack = getMatchPromotion(); - if(promotionPack != null){ - return true; - }else{ - return false; - } + if (reletedProductTotalPrice.compareTo(triggerPrice) >= 0) { + BigDecimal prePrice = slot.getLastestPriceStep().getCurrPrice(); + BigDecimal currPrice = prePrice.subtract(cutPrice); + + slot.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.PROMOTION_DISCOUNT) + .extId(promotionPack.getId().toString()) + .prePrice(prePrice) + .priceChange(currPrice.subtract(prePrice)) + .currPrice(currPrice) + .stepDesc(PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[满减]") + .build()); } - private PromotionPackVO getMatchPromotion(){ - PriceContext context = this.getContextBean(PriceContext.class); + } - List matchList = context.getPromotionPackList().stream().filter(promotionPackVO -> { - if(promotionPackVO.getPromotionType().equals(PromotionTypeEnum.FULL_CUT)){ - return true; - }else{ - return false; - } - }).collect(Collectors.toList()); + @Override + public boolean isAccess() { + // 过滤出优惠信息列表中有没有满减这个活动,如果有,则进入这个组件,反义就不进入 + Optional matchPromotion = getMatchPromotion(); + promotionPack = matchPromotion.orElse(null); + return matchPromotion.isPresent(); + } - if(CollectionUtils.isNotEmpty(matchList)){ - return matchList.get(0); - }else{ - return null; - } - } + private Optional getMatchPromotion() { + PriceContext context = this.getContextBean(PriceContext.class); + + return context.getPromotionPackList().stream() + .filter(promotionPackVO -> promotionPackVO.getPromotionType() + .equals(PromotionTypeEnum.FULL_CUT)) + .findFirst(); + } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/FullDiscountCmp.java b/src/main/java/com/yomahub/liteflow/example/component/FullDiscountCmp.java index 22aba7f..474da24 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/FullDiscountCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/FullDiscountCmp.java @@ -1,5 +1,8 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.FULL_DISCOUNT_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.bean.ProductPackVO; @@ -7,73 +10,75 @@ import com.yomahub.liteflow.example.bean.PromotionPackVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import com.yomahub.liteflow.example.enums.PromotionTypeEnum; import com.yomahub.liteflow.example.slot.PriceContext; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Component; - import java.math.BigDecimal; import java.math.RoundingMode; -import java.util.List; -import java.util.stream.Collectors; +import java.util.Objects; +import java.util.Optional; /** * 满折计算组件 + * + * @author bryan.zhang */ -@Component("fullDiscountCmp") +@LiteflowComponent(id = FULL_DISCOUNT_CMP, name = "满折计算组件") public class FullDiscountCmp extends NodeComponent { - @Override - public void process() throws Exception { - PriceContext context = this.getContextBean(PriceContext.class); - PromotionPackVO promotionPack = getMatchPromotion(); - /***这里Mock下根据优惠信息查到的满折信息为:满200,打9折***/ - BigDecimal triggerPrice = new BigDecimal(200); - BigDecimal discountRate = new BigDecimal("0.9"); + /** + * 满折-优惠包 + */ + private PromotionPackVO promotionPack; + + @Override + public void process() throws Exception { + if (Objects.isNull(promotionPack)) { + return; + } - //从PromotionPack对象中取到这个优惠关联的商品信息,判断是否超过了触发满折的金额 - BigDecimal reletedProductTotalPrice = new BigDecimal(0); - for(ProductPackVO productPack : promotionPack.getRelatedProductPackList()){ - reletedProductTotalPrice = reletedProductTotalPrice.add(productPack.getSalePrice().multiply(new BigDecimal(productPack.getCount()))); - } - if (reletedProductTotalPrice.compareTo(triggerPrice) >= 0){ - BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); - BigDecimal currPrice = prePrice.multiply(discountRate).setScale(2, RoundingMode.HALF_UP); + PriceContext context = this.getContextBean(PriceContext.class); - context.addPriceStep(new PriceStepVO(PriceTypeEnum.PROMOTION_DISCOUNT, - promotionPack.getId().toString(), - prePrice, - currPrice.subtract(prePrice), - currPrice, - PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[满折]")); - } + // 这里Mock下根据优惠信息查到的满折信息为:满200,打9折 + BigDecimal triggerPrice = BigDecimal.valueOf(200); + BigDecimal discountRate = new BigDecimal("0.9"); + //从PromotionPack对象中取到这个优惠关联的商品信息,判断是否超过了触发满折的金额 + BigDecimal reletedProductTotalPrice = BigDecimal.ZERO; + for (ProductPackVO productPack : promotionPack.getRelatedProductPackSet()) { + reletedProductTotalPrice = reletedProductTotalPrice.add(productPack.getSalePrice() + .multiply(BigDecimal.valueOf(productPack.getCount()))); } - @Override - public boolean isAccess() { - //过滤出优惠信息列表中有没有满折这个活动,如果有,则进入这个组件,反义就不进入 - PromotionPackVO promotionPack = getMatchPromotion(); - if(promotionPack != null){ - return true; - }else{ - return false; - } + if (reletedProductTotalPrice.compareTo(triggerPrice) >= 0) { + BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); + BigDecimal currPrice = prePrice.multiply(discountRate) + .setScale(2, RoundingMode.HALF_UP); + + context.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.PROMOTION_DISCOUNT) + .extId(promotionPack.getId().toString()) + .prePrice(prePrice) + .priceChange(currPrice.subtract(prePrice)) + .currPrice(currPrice) + .stepDesc(PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[满折]") + .build()); } - private PromotionPackVO getMatchPromotion(){ - PriceContext context = this.getContextBean(PriceContext.class); + } - List matchList = context.getPromotionPackList().stream().filter(promotionPackVO -> { - if(promotionPackVO.getPromotionType().equals(PromotionTypeEnum.FULL_DISCOUNT)){ - return true; - }else{ - return false; - } - }).collect(Collectors.toList()); + @Override + public boolean isAccess() { + // 过滤出优惠信息列表中有没有满折这个活动,如果有,则进入这个组件,反义就不进入 + Optional matchPromotion = getMatchPromotion(); + this.promotionPack = matchPromotion.orElse(null); - if(CollectionUtils.isNotEmpty(matchList)){ - return matchList.get(0); - }else{ - return null; - } - } + return matchPromotion.isPresent(); + } + + private Optional getMatchPromotion() { + PriceContext context = this.getContextBean(PriceContext.class); + + return context.getPromotionPackList().stream() + .filter(promotionPackVO -> promotionPackVO.getPromotionType() + .equals(PromotionTypeEnum.FULL_DISCOUNT)) + .findFirst(); + } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java b/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java index d78c174..52ee182 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/MemberDiscountCmp.java @@ -1,22 +1,24 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.MEMBER_DISCOUNT_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import com.yomahub.liteflow.example.slot.PriceContext; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.math.RoundingMode; /** * 会员折扣计算组件 - * + * * @author bryan.zhang */ -@Component("memberDiscountCmp") +@LiteflowComponent(id = MEMBER_DISCOUNT_CMP, name = "会员折扣计算组件") public class MemberDiscountCmp extends NodeComponent { @Override public void process() throws Exception { @@ -26,18 +28,20 @@ public class MemberDiscountCmp extends NodeComponent { // 这里Mock下通过memberCode去查会员等级表然后获取的会员折扣为9折的代码 BigDecimal memberDiscount = new BigDecimal("0.9"); - //进行计算会员折扣 + // 进行计算会员折扣 BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); - BigDecimal currPrice = prePrice.multiply(memberDiscount).setScale(2, RoundingMode.HALF_UP); - - //加入到价格步骤中 - context.addPriceStep(new PriceStepVO(PriceTypeEnum.MEMBER_DISCOUNT, - memberCode, - prePrice, - currPrice.subtract(prePrice), - currPrice, - PriceTypeEnum.MEMBER_DISCOUNT.getName())); - + BigDecimal currPrice = prePrice.multiply(memberDiscount) + .setScale(2, RoundingMode.HALF_UP); + + // 加入到价格步骤中 + context.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.MEMBER_DISCOUNT) + .extId(memberCode) + .prePrice(prePrice) + .priceChange(currPrice.subtract(prePrice)) + .currPrice(currPrice) + .stepDesc(PriceTypeEnum.MEMBER_DISCOUNT.getName()) + .build()); } @Override diff --git a/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java b/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java index 10f8dae..1c0bf00 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java +++ b/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java @@ -5,30 +5,45 @@ package com.yomahub.liteflow.example.component; * * @author 李小平 */ -public interface NodeIdConstant { +public class NodeIdConstant { /** * 初始化参数检查组件Id */ - String CHECK_CMP = "checkCmp"; + public static final String CHECK_CMP = "checkCmp"; /** * Slot初始化组件Id */ - String SLOT_INIT_CMP = "slotInitCmp"; + public static final String SLOT_INIT_CMP = "slotInitCmp"; /** * 优惠信息转换组件 */ - String PROMOTION_CONVERT_CMP = "promotionConvertCmp"; + public static final String PROMOTION_CONVERT_CMP = "promotionConvertCmp"; /** * 优惠券抵扣计算组件Id */ - String COUPON_CMP = "couponCmp"; + public static final String COUPON_CMP = "couponCmp"; /** * 步骤日志生成组件Id */ - String STEP_PRINT_CMP = "stepPrintCmp"; + public static final String STEP_PRINT_CMP = "stepPrintCmp"; + + /** + * 会员折扣计算组件Id + */ + public static final String MEMBER_DISCOUNT_CMP = "memberDiscountCmp"; + + /** + * 满减计算组件Id + */ + public static final String FULL_CUT_CMP = "fullCutCmp"; + + /** + * 满折计算组件Id + */ + public static final String FULL_DISCOUNT_CMP = "fullDiscountCmp"; } diff --git a/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java b/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java index fad118d..cd38b7d 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/PromotionConvertCmp.java @@ -2,7 +2,6 @@ package com.yomahub.liteflow.example.component; import static com.yomahub.liteflow.example.component.NodeIdConstant.PROMOTION_CONVERT_CMP; -import cn.hutool.core.collection.ListUtil; import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.ProductPackVO; @@ -23,8 +22,9 @@ import org.springframework.beans.BeanUtils; public class PromotionConvertCmp extends NodeComponent { @Override - public void process() throws Exception { + public void process() { PriceContext context = this.getContextBean(PriceContext.class); + // 优惠包 List promotionPackList = new ArrayList<>(); PromotionPackVO promotionPack; @@ -36,14 +36,13 @@ public class PromotionConvertCmp extends NodeComponent { for (PromotionInfoVO promotion : pack.getPromotionList()) { promotionPack = new PromotionPackVO(); promotionPack.setId(promotion.getId()); - if (promotionPackList.contains(promotionPack)) { - promotionPack = promotionPackList.get(promotionPackList.indexOf(promotionPack)); - if (!promotionPack.getRelatedProductPackList().contains(pack)) { - promotionPack.getRelatedProductPackList().add(pack); - } + int index = promotionPackList.indexOf(promotionPack); + if (index >= 0) { + promotionPack = promotionPackList.get(index); + promotionPack.getRelatedProductPackSet().add(pack); } else { BeanUtils.copyProperties(promotion, promotionPack); - promotionPack.setRelatedProductPackList(ListUtil.toList(pack)); + promotionPack.getRelatedProductPackSet().add(pack); promotionPackList.add(promotionPack); } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java b/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java index 67a162a..e958399 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java @@ -35,7 +35,7 @@ public class RushBuyCmp extends NodeComponent { BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); BigDecimal rushBuyDiscountPrice = new BigDecimal(0); - for(ProductPackVO productPack : promotionPack.getRelatedProductPackList()){ + for(ProductPackVO productPack : promotionPack.getRelatedProductPackSet()){ rushBuyDiscountPrice = rushBuyDiscountPrice.add(productPack.getSalePrice().subtract(rushBuyPrice) .multiply(new BigDecimal(productPack.getCount()))).setScale(2, RoundingMode.HALF_UP); } diff --git a/src/main/java/com/yomahub/liteflow/example/enums/PromotionTypeEnum.java b/src/main/java/com/yomahub/liteflow/example/enums/PromotionTypeEnum.java index b40ac0e..9a74837 100644 --- a/src/main/java/com/yomahub/liteflow/example/enums/PromotionTypeEnum.java +++ b/src/main/java/com/yomahub/liteflow/example/enums/PromotionTypeEnum.java @@ -1,13 +1,34 @@ package com.yomahub.liteflow.example.enums; +import lombok.Getter; + +/** + * 优惠类型 + * + * @author bryan.zhang + */ public enum PromotionTypeEnum { + + /** + * 满减 + */ FULL_CUT(1, "满减"), + + /** + * 满折 + */ FULL_DISCOUNT(2, "满折"), + + /** + * 抢购 + */ RUSH_BUY(3, "抢购"); - private Integer id; + @Getter + private final Integer id; - private String name; + @Getter + private final String name; PromotionTypeEnum(int id, String name){ this.id = id; -- Gitee From 872cb7d9f97bdd86a057b3718c14e99b1869541b Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Mon, 21 Nov 2022 18:00:49 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/component/RushBuyCmp.java | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java b/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java index e958399..6d32b93 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/RushBuyCmp.java @@ -1,5 +1,6 @@ package com.yomahub.liteflow.example.component; +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.bean.ProductPackVO; @@ -7,75 +8,76 @@ import com.yomahub.liteflow.example.bean.PromotionPackVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import com.yomahub.liteflow.example.enums.PromotionTypeEnum; import com.yomahub.liteflow.example.slot.PriceContext; -import org.apache.commons.collections4.CollectionUtils; -import org.springframework.stereotype.Component; +import java.util.Objects; +import java.util.Optional; import java.math.BigDecimal; import java.math.RoundingMode; -import java.util.List; -import java.util.stream.Collectors; + /** * 抢购计算组件 + * + * @author bryan.zhang */ -@Component("rushBuyCmp") +@LiteflowComponent(id = "rushBuyCmp", name = "抢购计算组件") public class RushBuyCmp extends NodeComponent { + + /** + * 抢购-优惠 + */ + private PromotionPackVO promotionPack; + @Override public void process() throws Exception { + if (Objects.isNull(promotionPack)) { + return; + } + PriceContext context = this.getContextBean(PriceContext.class); - PromotionPackVO promotionPack = getMatchPromotion(); - /** + /* * 这里Mock下根据优惠信息查到的抢购信息为:1块钱抢购 * 这里要注意的是,实际情况下,这个抢购活动所关联的商品,每个商品的抢购价格都不同 * 这里为了Mock方便,所关联的商品,每个SKU抢购价都是1元 * ps:抢购原则上和其他优惠活动互斥,这里就不写出互斥的逻辑了,在设置参数时请注意 **/ - BigDecimal rushBuyPrice = new BigDecimal(1); + BigDecimal rushBuyPrice = BigDecimal.ONE; BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); - BigDecimal rushBuyDiscountPrice = new BigDecimal(0); - for(ProductPackVO productPack : promotionPack.getRelatedProductPackSet()){ - rushBuyDiscountPrice = rushBuyDiscountPrice.add(productPack.getSalePrice().subtract(rushBuyPrice) - .multiply(new BigDecimal(productPack.getCount()))).setScale(2, RoundingMode.HALF_UP); + BigDecimal rushBuyDiscountPrice = BigDecimal.ZERO; + for (ProductPackVO productPack : promotionPack.getRelatedProductPackSet()){ + rushBuyDiscountPrice = rushBuyDiscountPrice.add(productPack.getSalePrice() + .subtract(rushBuyPrice) + .multiply(BigDecimal.valueOf(productPack.getCount()))) + .setScale(2, RoundingMode.HALF_UP); } BigDecimal currPrice = prePrice.subtract(rushBuyDiscountPrice); - context.addPriceStep(new PriceStepVO(PriceTypeEnum.PROMOTION_DISCOUNT, - promotionPack.getId().toString(), - prePrice, - currPrice.subtract(prePrice), - currPrice, - PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[抢购]")); - + context.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.PROMOTION_DISCOUNT) + .extId(promotionPack.getId().toString()) + .prePrice(prePrice) + .priceChange(currPrice.subtract(prePrice)) + .currPrice(currPrice) + .stepDesc(PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[抢购]") + .build()); } @Override public boolean isAccess() { //过滤出优惠信息列表中有没有抢购这个活动,如果有,则进入这个组件,反义就不进入 - PromotionPackVO promotionPack = getMatchPromotion(); - if(promotionPack != null){ - return true; - }else{ - return false; - } + Optional matchPromotion = getMatchPromotion(); + this.promotionPack = matchPromotion.orElse(null); + return matchPromotion.isPresent(); } - private PromotionPackVO getMatchPromotion(){ + private Optional getMatchPromotion(){ PriceContext context = this.getContextBean(PriceContext.class); - List matchList = context.getPromotionPackList().stream().filter(promotionPackVO -> { - if(promotionPackVO.getPromotionType().equals(PromotionTypeEnum.RUSH_BUY)){ - return true; - }else{ - return false; - } - }).collect(Collectors.toList()); + return context.getPromotionPackList().stream() + .filter(promotionPackVO -> promotionPackVO.getPromotionType().equals(PromotionTypeEnum.RUSH_BUY)) + .findFirst(); - if(CollectionUtils.isNotEmpty(matchList)){ - return matchList.get(0); - }else{ - return null; - } } } -- Gitee From dceaa17979ea70ff85e72b2bd8e1e61770e3a9b9 Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Mon, 21 Nov 2022 18:02:35 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yomahub/liteflow/example/component/PriceResultCmp.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java b/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java index 141b94d..8402463 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java @@ -27,10 +27,6 @@ public class PriceResultCmp extends NodeComponent { @Override public boolean isAccess() { PriceContext context = this.getContextBean(PriceContext.class); - if(CollectionUtils.isNotEmpty(context.getPriceStepList())){ - return true; - }else{ - return false; - } + return CollectionUtils.isNotEmpty(context.getPriceStepList()); } } -- Gitee From 928348be3ba5d25a80a334095d4342cd0a04b32d Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Mon, 21 Nov 2022 18:41:23 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/component/NodeIdConstant.java | 19 +++++++ .../example/component/OverseaPostageCmp.java | 10 ++-- .../example/component/PostageCmp.java | 49 +++++++++++-------- .../example/component/PostageCondCmp.java | 28 ++++++----- .../example/component/PriceResultCmp.java | 1 + 5 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java b/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java index 1c0bf00..30c28c9 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java +++ b/src/main/java/com/yomahub/liteflow/example/component/NodeIdConstant.java @@ -1,10 +1,14 @@ package com.yomahub.liteflow.example.component; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + /** * 流程组件Id常量声明 * * @author 李小平 */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class NodeIdConstant { /** * 初始化参数检查组件Id @@ -46,4 +50,19 @@ public class NodeIdConstant { * 满折计算组件Id */ public static final String FULL_DISCOUNT_CMP = "fullDiscountCmp"; + + /** + * 运费条件组件 + */ + public static final String POSTAGE_COND_CMP = "postageCondCmp"; + + /** + * 国内运费计算组件 + */ + public static final String POSTAGE_CMP = "postageCmp"; + + /** + * 境外购运费计算组件 + */ + public static final String OVERSEA_POSTAGE_CMP = "overseaPostageCmp"; } diff --git a/src/main/java/com/yomahub/liteflow/example/component/OverseaPostageCmp.java b/src/main/java/com/yomahub/liteflow/example/component/OverseaPostageCmp.java index bdb3112..5db373d 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/OverseaPostageCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/OverseaPostageCmp.java @@ -1,5 +1,8 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.OVERSEA_POSTAGE_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; @@ -10,15 +13,16 @@ import java.math.BigDecimal; /** * 境外购运费计算组件 + * @author bryan.zhang */ -@Component("overseaPostageCmp") +@LiteflowComponent(id = OVERSEA_POSTAGE_CMP, name = "境外购运费计算组件") public class OverseaPostageCmp extends NodeComponent { @Override public void process() throws Exception { PriceContext context = this.getContextBean(PriceContext.class); - /**这里Mock境外购运费的策略是:不管多少钱,都要加上15元运费**/ - BigDecimal postage = new BigDecimal(15); + // 这里Mock境外购运费的策略是:不管多少钱,都要加上15元运费 + BigDecimal postage = BigDecimal.valueOf(15); BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); BigDecimal currPrice = prePrice.add(postage); diff --git a/src/main/java/com/yomahub/liteflow/example/component/PostageCmp.java b/src/main/java/com/yomahub/liteflow/example/component/PostageCmp.java index 668e2dd..2f1a9a2 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/PostageCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/PostageCmp.java @@ -1,47 +1,56 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.POSTAGE_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.example.bean.PriceStepVO; import com.yomahub.liteflow.example.enums.PriceTypeEnum; import com.yomahub.liteflow.example.slot.PriceContext; -import org.springframework.stereotype.Component; import java.math.BigDecimal; /** * 国内运费计算组件 + * + * @author bryan.zhang */ -@Component("postageCmp") +@LiteflowComponent(id = POSTAGE_CMP, name = "国内运费计算组件") public class PostageCmp extends NodeComponent { @Override public void process() throws Exception { PriceContext context = this.getContextBean(PriceContext.class); - /**这里Mock运费的策略是:满99免运费,不满99需要10块钱运费**/ - BigDecimal triggerPrice = new BigDecimal(99); - BigDecimal postage = new BigDecimal(10); - //先把运费加上去 + // 这里Mock运费的策略是:满99免运费,不满99需要10块钱运费 + BigDecimal triggerPrice = BigDecimal.valueOf(99); + BigDecimal postage = BigDecimal.valueOf(10); + + // 先把运费加上去 BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice(); BigDecimal currPrice = prePrice.add(postage); - context.addPriceStep(new PriceStepVO(PriceTypeEnum.POSTAGE, - null, - prePrice, - currPrice.subtract(prePrice), - currPrice, - PriceTypeEnum.POSTAGE.getName())); + context.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.POSTAGE) + .extId(null) + .prePrice(prePrice) + .priceChange(currPrice.subtract(prePrice)) + .currPrice(currPrice) + .stepDesc(PriceTypeEnum.POSTAGE.getName()) + .build()); - //判断运费是否满99了,满了99就去掉运费 - if(prePrice.compareTo(triggerPrice) >= 0){ + // 判断运费是否满99了,满了99就去掉运费 + if (prePrice.compareTo(triggerPrice) >= 0) { prePrice = context.getLastestPriceStep().getCurrPrice(); currPrice = currPrice.subtract(postage); - context.addPriceStep(new PriceStepVO(PriceTypeEnum.POSTAGE_FREE, - null, - prePrice, - currPrice.subtract(prePrice), - currPrice, - PriceTypeEnum.POSTAGE_FREE.getName())); + context.addPriceStep(PriceStepVO.builder() + .priceType(PriceTypeEnum.POSTAGE_FREE) + .extId(null) + .prePrice(prePrice) + .priceChange(currPrice.subtract(prePrice)) + .currPrice(currPrice) + .stepDesc(PriceTypeEnum.POSTAGE_FREE.getName()) + .build()); } } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/PostageCondCmp.java b/src/main/java/com/yomahub/liteflow/example/component/PostageCondCmp.java index 4b920f2..b8cbb43 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/PostageCondCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/PostageCondCmp.java @@ -1,23 +1,25 @@ package com.yomahub.liteflow.example.component; +import static com.yomahub.liteflow.example.component.NodeIdConstant.OVERSEA_POSTAGE_CMP; +import static com.yomahub.liteflow.example.component.NodeIdConstant.POSTAGE_CMP; +import static com.yomahub.liteflow.example.component.NodeIdConstant.POSTAGE_COND_CMP; + +import com.yomahub.liteflow.annotation.LiteflowComponent; import com.yomahub.liteflow.core.NodeSwitchComponent; import com.yomahub.liteflow.example.slot.PriceContext; -import org.springframework.stereotype.Component; /** * 运费条件组件 + * + * @author bryan.zhang */ -@Component("postageCondCmp") +@LiteflowComponent(id = POSTAGE_COND_CMP, name = "运费条件组件") public class PostageCondCmp extends NodeSwitchComponent { - @Override - public String processSwitch() throws Exception { - PriceContext context = this.getContextBean(PriceContext.class); - //根据参数oversea来判断是否境外购,转到相应的组件 - boolean oversea = context.isOversea(); - if(oversea){ - return "overseaPostageCmp"; - }else{ - return "postageCmp"; - } - } + + @Override + public String processSwitch() { + PriceContext context = this.getContextBean(PriceContext.class); + // 根据参数oversea来判断是否境外购,转到相应的组件 + return context.isOversea() ? OVERSEA_POSTAGE_CMP : POSTAGE_CMP; + } } diff --git a/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java b/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java index 8402463..84d01ff 100644 --- a/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java +++ b/src/main/java/com/yomahub/liteflow/example/component/PriceResultCmp.java @@ -10,6 +10,7 @@ import java.math.BigDecimal; /** * 订单最终价格计算器 + * @author LiXiaoPing */ @Component("priceResultCmp") public class PriceResultCmp extends NodeComponent { -- Gitee From 4522822698f220a34d612960a32c7ef7a28d570c Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Mon, 21 Nov 2022 19:15:31 +0800 Subject: [PATCH 06/10] =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++- .../example/LiteflowExampleApplication.java | 41 ++++++++++++++++++- .../controller/PriceExampleController.java | 22 +++++----- .../example/enums/OrderChannelEnum.java | 35 +++++++++++++++- .../liteflow/example/enums/SkuSourceEnum.java | 31 +++++++++++--- src/main/resources/application.properties | 2 - src/main/resources/application.yml | 10 +++++ 7 files changed, 127 insertions(+), 22 deletions(-) delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml diff --git a/README.md b/README.md index 8161038..07cdd39 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ 此工程是[LiteFlow](https://gitee.com/dromara/liteFlow)框架的示例工程。 -master目前是基于v2.8.0版本的 \ No newline at end of file +## 前端UI + +http://localhost:8580/ + +![image-20221121191123474](Client-GUI.png) + +master目前是基于v2.9.3版本的 \ No newline at end of file diff --git a/src/main/java/com/yomahub/liteflow/example/LiteflowExampleApplication.java b/src/main/java/com/yomahub/liteflow/example/LiteflowExampleApplication.java index dc681c9..00308dd 100644 --- a/src/main/java/com/yomahub/liteflow/example/LiteflowExampleApplication.java +++ b/src/main/java/com/yomahub/liteflow/example/LiteflowExampleApplication.java @@ -1,13 +1,52 @@ package com.yomahub.liteflow.example; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Optional; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.core.env.Environment; +/** + * @author bryan.zhang + */ @SpringBootApplication +@Slf4j public class LiteflowExampleApplication { public static void main(String[] args) { - SpringApplication.run(LiteflowExampleApplication.class, args); + SpringApplication app = new SpringApplication(LiteflowExampleApplication.class); + Environment env = app.run(args).getEnvironment(); + logApplicationStartup(env); + } + + private static void logApplicationStartup(Environment env) { + String protocol = Optional.ofNullable(env.getProperty("server.ssl.key-store")).map(key -> "https").orElse("http"); + String serverPort = env.getProperty("server.port"); + String contextPath = Optional + .ofNullable(env.getProperty("server.servlet.context-path")) + .filter(StringUtils::isNotBlank) + .orElse("/"); + String hostAddress = "localhost"; + try { + hostAddress = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.warn("The host name could not be determined, using `localhost` as fallback"); + } + log.info( + "\n----------------------------------------------------------\n\t" + + "Application '{}' is running! Access URLs:\n\t" + + "Local: \t\t{}://localhost:{}{}\n\t" + + "External: \t{}://{}:{}{}\n\t" + + "Profile(s): \t{}" + + "\n----------------------------------------------------------", + env.getProperty("spring.application.name"), + protocol, serverPort, contextPath, + protocol, hostAddress, serverPort, contextPath, + env.getActiveProfiles() + ); } } diff --git a/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java b/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java index a78e182..b493a1e 100644 --- a/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java +++ b/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java @@ -22,32 +22,32 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; +/** + * @author bryan.zhang + */ @Controller public class PriceExampleController { @Resource private FlowExecutor flowExecutor; - @RequestMapping(value = "/", method = RequestMethod.GET) + @GetMapping(value = "/") public String index(ModelMap modelMap){ PriceCalcReqVO req = mockReq(); String json = JSON.toJSONString(req); - modelMap.put("req",json); + modelMap.put("req", json); return "index"; } - @RequestMapping(value = "/submit", method = RequestMethod.POST) + @PostMapping (value = "/submit") @ResponseBody public String submit(@Nullable @RequestBody String reqData){ - try{ - PriceCalcReqVO req = JSON.parseObject(reqData,PriceCalcReqVO.class); - LiteflowResponse response = flowExecutor.execute2Resp("mainChain", req, PriceContext.class); - return response.getContextBean(PriceContext.class).getPrintLog(); - }catch (Throwable t){ - t.printStackTrace(); - return "error"; - } + PriceCalcReqVO req = JSON.parseObject(reqData,PriceCalcReqVO.class); + LiteflowResponse response = flowExecutor.execute2Resp("mainChain", req, PriceContext.class); + + return response.getContextBean(PriceContext.class).getPrintLog(); + } private PriceCalcReqVO mockReq(){ diff --git a/src/main/java/com/yomahub/liteflow/example/enums/OrderChannelEnum.java b/src/main/java/com/yomahub/liteflow/example/enums/OrderChannelEnum.java index ee639f2..12af0cb 100644 --- a/src/main/java/com/yomahub/liteflow/example/enums/OrderChannelEnum.java +++ b/src/main/java/com/yomahub/liteflow/example/enums/OrderChannelEnum.java @@ -1,17 +1,48 @@ package com.yomahub.liteflow.example.enums; +import lombok.Getter; + +/** + * @author bryan.zhang + */ + public enum OrderChannelEnum { + /** + * APP渠道 + */ APP(1,"APP渠道"), + + /** + * 小程序渠道 + */ MINI_PROGRAM(2,"小程序渠道"), + + /** + * 微信H5 + */ WX_H5(3,"微信H5"), + + /** + * 移动H5渠道 + */ MOBILE_H5(4,"移动H5渠道"), + + /** + * PC主站渠道 + */ WEB_PORTAL(5,"PC主站渠道"), + + /** + * 线下门店渠道 + */ OFFLINE_STORE(5,"线下门店渠道"); - private Integer id; + @Getter + private final Integer id; - private String name; + @Getter + private final String name; OrderChannelEnum(int id, String name){ this.id = id; diff --git a/src/main/java/com/yomahub/liteflow/example/enums/SkuSourceEnum.java b/src/main/java/com/yomahub/liteflow/example/enums/SkuSourceEnum.java index 508cc74..9f058af 100644 --- a/src/main/java/com/yomahub/liteflow/example/enums/SkuSourceEnum.java +++ b/src/main/java/com/yomahub/liteflow/example/enums/SkuSourceEnum.java @@ -7,18 +7,39 @@ */ package com.yomahub.liteflow.example.enums; +import lombok.Getter; + /** * 商品来源枚举 + * @author bryan.zhang */ public enum SkuSourceEnum { - RAW(0, "自购"), - GIFT(3, "买赠"), - ADDITION(4,"换购"), + + /** + * 自购 + */ + RAW(0, "自购"), + + /** + * 买赠 + */ + GIFT(3, "买赠"), + + /** + * 换购 + */ + ADDITION(4,"换购"), + + /** + * 权益商品 + */ BENEFIT(5,"权益商品"); - private Integer code; + @Getter + private final Integer code; - private String name; + @Getter + private final String name; SkuSourceEnum(Integer code, String name) { this.code = code; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 7e09a44..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -server.port=8580 -liteflow.ruleSource=liteflow/*.el.xml diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..ad72fd6 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,10 @@ + +liteflow: + rule-source: liteflow/*.el.xml +server: + port: 8580 +spring: + application: + name: liteflow-example + profiles: + active: default -- Gitee From 971edef04f1e857f813d50245653590187c655f9 Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Mon, 21 Nov 2022 19:15:43 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client-GUI.png | Bin 0 -> 83031 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Client-GUI.png diff --git a/Client-GUI.png b/Client-GUI.png new file mode 100644 index 0000000000000000000000000000000000000000..fde347fbae2bfbe1b2524fd857efbfc221336750 GIT binary patch literal 83031 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 LES2}<_dos%z1tBX literal 0 HcmV?d00001 -- Gitee From fd5d5e75467bee94dbcae1fe72d3af1a1eb7cc69 Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Tue, 22 Nov 2022 09:28:41 +0800 Subject: [PATCH 08/10] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E9=87=8D=E6=9E=84:Pric?= =?UTF-8?q?eExampleController?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 8 + .../liteflow/example/bean/PriceCalcReqVO.java | 16 +- .../liteflow/example/bean/ProductPackVO.java | 2 + .../example/bean/PromotionInfoVO.java | 2 + .../controller/PriceExampleController.java | 144 +++++++++++------- 5 files changed, 110 insertions(+), 62 deletions(-) diff --git a/pom.xml b/pom.xml index 680faef..4ced311 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,14 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + diff --git a/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java b/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java index a99f03e..24f6bb2 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/PriceCalcReqVO.java @@ -3,9 +3,11 @@ package com.yomahub.liteflow.example.bean; import com.yomahub.liteflow.example.enums.OrderChannelEnum; import java.util.List; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; /** * 订单价格计算请求参数 @@ -13,9 +15,11 @@ import lombok.ToString; * @author bryan.zhang */ -@ToString -@Getter -@Setter +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) public class PriceCalcReqVO { private Long id; diff --git a/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java b/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java index 2a549cb..1edab7a 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/ProductPackVO.java @@ -8,6 +8,7 @@ import java.util.Objects; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import lombok.experimental.Accessors; /** * 商品信息 @@ -18,6 +19,7 @@ import lombok.ToString; @ToString @Getter @Setter +@Accessors(chain = true) public class ProductPackVO { /* diff --git a/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java b/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java index 261eca6..3eb32c4 100644 --- a/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java +++ b/src/main/java/com/yomahub/liteflow/example/bean/PromotionInfoVO.java @@ -3,6 +3,7 @@ package com.yomahub.liteflow.example.bean; import com.yomahub.liteflow.example.enums.PromotionTypeEnum; import java.util.Objects; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @@ -15,6 +16,7 @@ import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor +@Builder public class PromotionInfoVO { /** diff --git a/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java b/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java index b493a1e..b390ef7 100644 --- a/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java +++ b/src/main/java/com/yomahub/liteflow/example/controller/PriceExampleController.java @@ -1,6 +1,5 @@ package com.yomahub.liteflow.example.controller; -import cn.hutool.core.collection.ListUtil; import com.alibaba.fastjson.JSON; import com.yomahub.liteflow.core.FlowExecutor; import com.yomahub.liteflow.example.bean.PriceCalcReqVO; @@ -12,6 +11,9 @@ import com.yomahub.liteflow.example.enums.PromotionTypeEnum; import com.yomahub.liteflow.example.enums.SkuSourceEnum; import com.yomahub.liteflow.example.slot.PriceContext; import com.yomahub.liteflow.flow.LiteflowResponse; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.ThreadLocalRandom; import org.springframework.lang.Nullable; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; @@ -51,72 +53,102 @@ public class PriceExampleController { } private PriceCalcReqVO mockReq(){ - PriceCalcReqVO req = new PriceCalcReqVO(); - req.setOrderNo("SO2020070611120001"); - req.setOversea(false); - req.setMemberCode("M21152"); - req.setOrderChannel(OrderChannelEnum.APP); - req.setCouponId(80081L); - List productPackList = new ArrayList<>(); - req.setProductPackList(productPackList); + return PriceCalcReqVO.builder() + .orderNo("SO2020070611120001") + .oversea(ThreadLocalRandom.current().nextBoolean()) + .memberCode("M21152") + .orderChannel(OrderChannelEnum.APP) + .couponId(80081L) + .productPackList(initProductPackVos()) + .build(); + } + /** + * 初始化商品信息列表 + */ + private List initProductPackVos() { + List productPackList = new ArrayList<>(); ProductPackVO productPack = new ProductPackVO(); - productPack.setProductId(5001L); - productPack.setProductCode("PD5001XC"); - productPack.setSkuId(67001441L); - productPack.setSkuCode("SKU5001XC001"); - productPack.setSkuName("夏季运动女式短裙M"); - productPack.setSkuSource(SkuSourceEnum.RAW); - productPack.setCategory(CategoryEnum.CLOTHES); - productPack.setSalePrice(new BigDecimal("139.00")); - productPack.setCount(2); - productPack.setPromotionList(ListUtil.toList( - new PromotionInfoVO(1001L,"PM1001","夏季满减活动", PromotionTypeEnum.FULL_CUT), - new PromotionInfoVO(1002L,"PM1002","夏季满折活动", PromotionTypeEnum.FULL_DISCOUNT))); + productPack.setProductId(5001L) + .setProductCode("PD5001XC") + .setSkuId(67001441L) + .setSkuCode("SKU5001XC001") + .setSkuName("夏季运动女式短裙M") + .setSkuSource(SkuSourceEnum.RAW) + .setCategory(CategoryEnum.CLOTHES) + .setSalePrice(new BigDecimal("139.00")) + .setCount(ThreadLocalRandom.current().nextInt(2, 10)) + .setPromotionList(Arrays.asList( + PromotionInfoVO.builder() + .id(1001L) + .promotionCode("PM1001") + .promotionName("夏季满减活动") + .promotionType(PromotionTypeEnum.FULL_CUT) + .build(), + PromotionInfoVO.builder() + .id(1002L) + .promotionCode("PM1002") + .promotionName("夏季满折活动") + .promotionType(PromotionTypeEnum.FULL_DISCOUNT) + .build())); productPackList.add(productPack); productPack = new ProductPackVO(); - productPack.setProductId(6001L); - productPack.setProductCode("PD6001XC"); - productPack.setSkuId(67002334L); - productPack.setSkuCode("SKU6001XC001"); - productPack.setSkuName("男士迷彩短袜均码"); - productPack.setSkuSource(SkuSourceEnum.RAW); - productPack.setCategory(CategoryEnum.CLOTHES); - productPack.setSalePrice(new BigDecimal("59.00")); - productPack.setCount(3); - productPack.setPromotionList(ListUtil.toList( - new PromotionInfoVO(1001L,"PM1001","夏季满减活动", PromotionTypeEnum.FULL_CUT))); + productPack.setProductId(6001L) + .setProductCode("PD6001XC") + .setSkuId(67002334L) + .setSkuCode("SKU6001XC001") + .setSkuName("男士迷彩短袜均码") + .setSkuSource(SkuSourceEnum.RAW) + .setCategory(CategoryEnum.CLOTHES) + .setSalePrice(new BigDecimal("59.00")) + .setCount(ThreadLocalRandom.current().nextInt(3, 20)) + .setPromotionList(Collections.singletonList( + PromotionInfoVO.builder() + .id(1001L) + .promotionCode("PM1001") + .promotionName("夏季满减活动") + .promotionType(PromotionTypeEnum.FULL_CUT) + .build())); productPackList.add(productPack); productPack = new ProductPackVO(); - productPack.setProductId(8001L); - productPack.setProductCode("PD8001XC"); - productPack.setSkuId(87002001L); - productPack.setSkuCode("SKU8001XC001"); - productPack.setSkuName("纯棉毛巾"); - productPack.setSkuSource(SkuSourceEnum.RAW); - productPack.setCategory(CategoryEnum.DAILY_USE); - productPack.setSalePrice(new BigDecimal("28.00")); - productPack.setCount(5); - productPack.setPromotionList(ListUtil.toList( - new PromotionInfoVO(1002L,"PM1002","夏季满折活动", PromotionTypeEnum.FULL_DISCOUNT))); + productPack.setProductId(8001L) + .setProductCode("PD8001XC") + .setSkuId(87002001L) + .setSkuCode("SKU8001XC001") + .setSkuName("纯棉毛巾") + .setSkuSource(SkuSourceEnum.RAW) + .setCategory(CategoryEnum.DAILY_USE) + .setSalePrice(new BigDecimal("28.00")) + .setCount(ThreadLocalRandom.current().nextInt(5, 100)) + .setPromotionList(Collections.singletonList( + PromotionInfoVO.builder() + .id(1002L) + .promotionCode("PM1002") + .promotionName("夏季满折活动") + .promotionType(PromotionTypeEnum.FULL_DISCOUNT) + .build())); productPackList.add(productPack); productPack = new ProductPackVO(); - productPack.setProductId(9001L); - productPack.setProductCode("PD9001XC"); - productPack.setSkuId(97552001L); - productPack.setSkuCode("SKU9001XC001"); - productPack.setSkuName("杀菌护手凝胶"); - productPack.setSkuSource(SkuSourceEnum.RAW); - productPack.setCategory(CategoryEnum.DAILY_USE); - productPack.setSalePrice(new BigDecimal("30")); - productPack.setCount(2); - productPack.setPromotionList(ListUtil.toList( - new PromotionInfoVO(1003L,"PM1003","618抢购活动", PromotionTypeEnum.RUSH_BUY))); + productPack.setProductId(9001L) + .setProductCode("PD9001XC") + .setSkuId(97552001L) + .setSkuCode("SKU9001XC001") + .setSkuName("杀菌护手凝胶") + .setSkuSource(SkuSourceEnum.RAW) + .setCategory(CategoryEnum.DAILY_USE) + .setSalePrice(new BigDecimal("30")) + .setCount(ThreadLocalRandom.current().nextInt(2, 6)) + .setPromotionList(Collections.singletonList( + PromotionInfoVO.builder() + .id(1003L) + .promotionCode("PM1003") + .promotionName("618抢购活动") + .promotionType(PromotionTypeEnum.RUSH_BUY) + .build())); productPackList.add(productPack); - - return req; + return productPackList; } } -- Gitee From 9f49bb1421999aead0920d0422d729716ed81beb Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Tue, 22 Nov 2022 09:32:09 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E4=BF=AE=E8=AE=A2Readme.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 07cdd39..7ac7bbb 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,13 @@ ## 前端UI -http://localhost:8580/ +---------------------------------------------------------- + Application 'liteflow-example' is running! Access URLs: + Local: http://localhost:8580/ + External: http://10.1.6.92:8580/ + Profile(s): [default] +---------------------------------------------------------- ![image-20221121191123474](Client-GUI.png) -master目前是基于v2.9.3版本的 \ No newline at end of file +master目前是基于v2.9.3版本的 -- Gitee From f0bc5358895b4e73d5d1829179dd44ce92136dd7 Mon Sep 17 00:00:00 2001 From: lixiaoping <李小平17773406760@189.cn> Date: Tue, 22 Nov 2022 09:40:36 +0800 Subject: [PATCH 10/10] =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=9ACategoryEnum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../liteflow/example/enums/CategoryEnum.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/yomahub/liteflow/example/enums/CategoryEnum.java b/src/main/java/com/yomahub/liteflow/example/enums/CategoryEnum.java index 43ed3f5..4f3ea2f 100644 --- a/src/main/java/com/yomahub/liteflow/example/enums/CategoryEnum.java +++ b/src/main/java/com/yomahub/liteflow/example/enums/CategoryEnum.java @@ -1,13 +1,34 @@ package com.yomahub.liteflow.example.enums; +import lombok.Getter; + +/** + * 商品目录 + * + * @author bryan.zhang + */ + public enum CategoryEnum { + /** + * 食品 + */ FOOD(1,"食品"), + + /** + * 衣服 + */ CLOTHES(2,"衣服"), + + /** + * 生活用品 + */ DAILY_USE(3,"生活用品"); - private Integer id; + @Getter + private final Integer id; - private String name; + @Getter + private final String name; CategoryEnum(int id, String name){ this.id = id; -- Gitee