ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/GoodsSeckill.java
@@ -32,9 +32,9 @@ @TableId(value = "id", type = IdType.AUTO) private Integer id; @ApiModelProperty(value = "商品id") @TableField("goods_id") private Integer goodsId; @ApiModelProperty(value = "秒杀活动主表") @TableField("seckill_activity_info_id") private Integer seckillActivityInfoId; @ApiModelProperty(value = "会员级别(1=普通会员,2=黄金会员,3=钻石会员,4=准代理,5=代理,6=总代,7=合伙人)") @TableField("vip") @@ -99,6 +99,10 @@ @ApiModelProperty(value = "绑定门店上级门店可获得返佣积分") @TableField("bound_shop_superiors_points") private Integer boundShopSuperiorsPoints; @ApiModelProperty(value = "活动结束时间") @TableField(exist = false) private Long endTime; } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/GoodsBargainPriceClientFallbackFactory.java
New file @@ -0,0 +1,21 @@ package com.ruoyi.other.api.factory; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.GoodsBargainPriceDetail; import com.ruoyi.other.api.feignClient.GoodsBargainPriceClient; import com.ruoyi.other.api.vo.GetGoodsBargainPrice; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.openfeign.FallbackFactory; @Slf4j public class GoodsBargainPriceClientFallbackFactory implements FallbackFactory<GoodsBargainPriceClient> { @Override public GoodsBargainPriceClient create(Throwable cause) { return new GoodsBargainPriceClient(){ @Override public R<GoodsBargainPriceDetail> getGoodsBargainPrice(GetGoodsBargainPrice goodsBargainPrice) { return R.fail("根据商品id和会员等级获取门店特价失败:" + cause.getMessage()); } }; } } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/SeckillActivityInfoClientFallbackFactory.java
New file @@ -0,0 +1,20 @@ package com.ruoyi.other.api.factory; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.GoodsSeckill; import com.ruoyi.other.api.feignClient.SeckillActivityInfoClient; import com.ruoyi.other.api.vo.GetSeckillActivityInfo; import lombok.extern.slf4j.Slf4j; @Slf4j public class SeckillActivityInfoClientFallbackFactory implements org.springframework.cloud.openfeign.FallbackFactory<SeckillActivityInfoClient> { @Override public SeckillActivityInfoClient create(Throwable cause) { return new SeckillActivityInfoClient(){ @Override public R<GoodsSeckill> getSeckillActivityInfo(GetSeckillActivityInfo info) { return R.fail("根据商品id和会员等级获取对应的秒杀活动失败:" + cause.getMessage()); } }; } } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/GoodsBargainPriceClient.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.other.api.feignClient; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.GoodsBargainPriceDetail; import com.ruoyi.other.api.factory.GoodsBargainPriceClientFallbackFactory; import com.ruoyi.other.api.vo.GetGoodsBargainPrice; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; /** * @author zhibing.pu * @Date 2024/11/28 10:53 */ @FeignClient(contextId = "GoodsBargainPriceClient", value = ServiceNameConstants.ORDER_SERVICE, fallbackFactory = GoodsBargainPriceClientFallbackFactory.class) public interface GoodsBargainPriceClient { /** * 根据商品id和会员等级获取门店特价 * @param goodsBargainPrice * @return */ @PostMapping("/goods-bargain-price/getGoodsBargainPrice") R<GoodsBargainPriceDetail> getGoodsBargainPrice(@RequestBody GetGoodsBargainPrice goodsBargainPrice); } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/SeckillActivityInfoClient.java
New file @@ -0,0 +1,27 @@ package com.ruoyi.other.api.feignClient; import com.ruoyi.common.core.constant.ServiceNameConstants; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.GoodsSeckill; import com.ruoyi.other.api.factory.SeckillActivityInfoClientFallbackFactory; import com.ruoyi.other.api.vo.GetSeckillActivityInfo; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; /** * @author zhibing.pu * @Date 2024/11/28 10:38 */ @FeignClient(contextId = "SeckillActivityInfoClient", value = ServiceNameConstants.ORDER_SERVICE, fallbackFactory = SeckillActivityInfoClientFallbackFactory.class) public interface SeckillActivityInfoClient { /** * 根据商品id和会员等级获取对应的秒杀活动 * @param info * @return */ @PostMapping("/seckill-activity-info/getSeckillActivityInfo") R<GoodsSeckill> getSeckillActivityInfo(@RequestBody GetSeckillActivityInfo info); } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/vo/GetGoodsBargainPrice.java
New file @@ -0,0 +1,23 @@ package com.ruoyi.other.api.vo; import lombok.Data; /** * @author zhibing.pu * @Date 2024/11/28 10:47 */ @Data public class GetGoodsBargainPrice { /** * 商品id */ private Integer goodsId; /** * 会员 */ private Integer vip; /** * 门店id */ private Integer shopId; } ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/vo/GetSeckillActivityInfo.java
New file @@ -0,0 +1,19 @@ package com.ruoyi.other.api.vo; import lombok.Data; /** * @author zhibing.pu * @Date 2024/11/28 10:33 */ @Data public class GetSeckillActivityInfo { /** * 商品id */ private Integer goodsId; /** * 会员 */ private Integer vip; } ruoyi-api/ruoyi-api-other/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1,4 +1,6 @@ com.ruoyi.other.api.factory.GoodsClientFallbackFactory com.ruoyi.other.api.factory.GoodsShopClientFallbackFactory com.ruoyi.other.api.factory.GoodsAreaClientFallbackFactory com.ruoyi.other.api.factory.GoodsVipClientFallbackFactory com.ruoyi.other.api.factory.GoodsVipClientFallbackFactory com.ruoyi.other.api.factory.SeckillActivityInfoClientFallbackFactory com.ruoyi.other.api.factory.GoodsBargainPriceClientFallbackFactory ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/ShoppingCartController.java
@@ -2,6 +2,7 @@ import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.page.TableDataInfo; import com.ruoyi.order.service.ShoppingCartService; import com.ruoyi.order.vo.*; @@ -46,9 +47,8 @@ @ResponseBody @PostMapping("/setGoodsNumber") @ApiOperation(value = "修改购物车数量", tags = {"商城-购物车-小程序"}) public R<Void> setGoodsNumber(@RequestBody SetGoodsNumber setGoodsNumber){ // todo 待完善 pu return R.ok(); public AjaxResult setGoodsNumber(@RequestBody SetGoodsNumber setGoodsNumber){ return shoppingCartService.setGoodsNumber(setGoodsNumber); } @@ -56,18 +56,18 @@ @ResponseBody @PostMapping("/confirmOrder") @ApiOperation(value = "确定购物车订单", tags = {"商城-购物车-小程序"}) public R<ConfirmOrderVo> confirmOrder(@RequestBody ConfirmOrder confirmOrder){ public AjaxResult<ConfirmOrderVo> confirmOrder(@RequestBody ConfirmOrder confirmOrder){ // todo 待完善 pu return R.ok(); return AjaxResult.success(); } @ResponseBody @PostMapping("/shoppingCartPayment") @ApiOperation(value = "购物车订单支付", tags = {"商城-购物车-小程序"}) public R<Void> shoppingCartPayment(@RequestBody ShoppingCartPayment shoppingCartPayment){ public AjaxResult<Void> shoppingCartPayment(@RequestBody ShoppingCartPayment shoppingCartPayment){ // todo 待完善 pu return R.ok(); return AjaxResult.success(); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/ShoppingCartService.java
@@ -1,8 +1,11 @@ package com.ruoyi.order.service; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.order.vo.MyShoppingCartVo; import com.ruoyi.order.vo.SetGoodsNumber; import model.ShoppingCart; import org.springframework.web.bind.annotation.RequestBody; import java.util.List; @@ -22,4 +25,12 @@ * @param shoppingCart */ void addGoods(ShoppingCart shoppingCart); /** * 修改购物车数量 * @param setGoodsNumber * @return */ AjaxResult setGoodsNumber(SetGoodsNumber setGoodsNumber); } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/ShoppingCartServiceImpl.java
@@ -4,24 +4,25 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.api.feignClient.AppUserClient; import com.ruoyi.account.api.model.AppUser; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.security.service.TokenService; import com.ruoyi.order.mapper.ShoppingCartMapper; import com.ruoyi.order.service.ShoppingCartService; import com.ruoyi.order.vo.MyShoppingCartVo; import com.ruoyi.other.api.domain.Goods; import com.ruoyi.other.api.domain.GoodsArea; import com.ruoyi.other.api.domain.GoodsShop; import com.ruoyi.other.api.domain.GoodsVip; import com.ruoyi.other.api.feignClient.GoodsAreaClient; import com.ruoyi.other.api.feignClient.GoodsClient; import com.ruoyi.other.api.feignClient.GoodsShopClient; import com.ruoyi.other.api.feignClient.GoodsVipClient; import com.ruoyi.order.vo.SetGoodsNumber; import com.ruoyi.other.api.domain.*; import com.ruoyi.other.api.feignClient.*; import com.ruoyi.other.api.vo.GetGoodsBargainPrice; import com.ruoyi.other.api.vo.GetSeckillActivityInfo; import lombok.Data; import model.ShoppingCart; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service @@ -44,6 +45,12 @@ @Resource private GoodsVipClient goodsVipClient; @Resource private SeckillActivityInfoClient seckillActivityInfoClient; @Resource private GoodsBargainPriceClient goodsBargainPriceClient; @@ -77,21 +84,28 @@ vo.setHomePicture(goods.getHomePagePicture()); vo.setName(goods.getName()); GoodsArea area = new GoodsArea(); area.setDistrictsCode(appUser.getDistrictCode()); area.setCityCode(appUser.getCityCode()); area.setProvinceCode(appUser.getProvinceCode()); area.setVip(appUser.getVipId()); GoodsArea goodsArea = goodsAreaClient.getGoodsArea(area).getData(); if(null == goodsArea){ GoodsVip goodsVip = goodsVipClient.getGoodsVip(appUser.getVipId()).getData(); //获取支付价格 Price price = getPrice(appUser, shoppingCart.getGoodsId(), shopId); if(null == price){ //使用商品的基础价格 price.setCash(1 == goods.getCashPayment() ? goods.getSellingPrice() : null); price.setPoint(1 == goods.getPointPayment() ? goods.getIntegral() : null); } vo.setSellingPrice(goods); //构建价格展示内容 String sellingPrice = ""; if(null != price.getCash() && null != price.getPoint()){ sellingPrice = price.getCash() + "或" + price.getPoint() + "积分"; } if(null != price.getCash() && null == price.getPoint()){ sellingPrice = price.getCash() + ""; } if(null == price.getCash() && null != price.getPoint()){ sellingPrice = price.getPoint() + "积分"; } vo.setSellingPrice(sellingPrice); vo.setEndTime(price.getEndTime()); vo.setOriginalPrice(goods.getOriginalPrice().toString()); vo.setNumber(shoppingCart.getNumber()); vo.setEndTime(); GoodsShop goodsShop = new GoodsShop(); goodsShop.setGoodsId(shoppingCart.getGoodsId()); goodsShop.setShopId(shopId); @@ -101,6 +115,91 @@ } return page; } /** * 获取支付价格 * @param appUser * @param goodsId * @param shopId * @return */ public Price getPrice(AppUser appUser, Integer goodsId, Integer shopId){ //获取支付价格 //秒杀活动>门店特价>地区价格>会员价格 //判断是否有秒杀活动 Price price = new Price(); GetSeckillActivityInfo info = new GetSeckillActivityInfo(); info.setGoodsId(goodsId); info.setVip(appUser.getVipId()); GoodsSeckill goodsSeckill = seckillActivityInfoClient.getSeckillActivityInfo(info).getData(); if(null == goodsSeckill){ //没有秒杀价,则判断门店特价 GetGoodsBargainPrice goodsBargainPrice = new GetGoodsBargainPrice(); goodsBargainPrice.setGoodsId(goodsId); goodsBargainPrice.setVip(appUser.getVipId()); goodsBargainPrice.setShopId(shopId); GoodsBargainPriceDetail bargainPriceDetail = goodsBargainPriceClient.getGoodsBargainPrice(goodsBargainPrice).getData(); if(null == bargainPriceDetail){ //没有门店特价,判断地区价格配置 GoodsArea area = new GoodsArea(); area.setDistrictsCode(appUser.getDistrictCode()); area.setCityCode(appUser.getCityCode()); area.setProvinceCode(appUser.getProvinceCode()); area.setVip(appUser.getVipId()); GoodsArea goodsArea = goodsAreaClient.getGoodsArea(area).getData(); if(null == goodsArea){ //没有地区价格,则使用会员价格 GoodsVip goodsVip = goodsVipClient.getGoodsVip(appUser.getVipId()).getData(); if(null == goodsVip){ //没有配置价格,直接使用原始基础价格 return null; }else{ price.setCash(goodsVip.getSellingPrice()); price.setPoint(goodsVip.getIntegral()); } }else{ price.setCash(goodsArea.getSellingPrice()); price.setPoint(goodsArea.getIntegral()); } }else{ price.setCash(bargainPriceDetail.getSellingPrice()); price.setPoint(bargainPriceDetail.getIntegral()); } }else{ //构建价格数据 if(goodsSeckill.getCashPayment() == 1 && goodsSeckill.getPointPayment() == 1){ price.setCash(goodsSeckill.getSellingPrice()); price.setPoint(goodsSeckill.getIntegral()); } if(goodsSeckill.getCashPayment() == 1 && goodsSeckill.getPointPayment() == 0){ price.setCash(goodsSeckill.getSellingPrice()); } if(goodsSeckill.getCashPayment() == 0 && goodsSeckill.getPointPayment() == 1){ price.setPoint(goodsSeckill.getIntegral()); } price.setEndTime(goodsSeckill.getEndTime()); } return price; } @Data class Price { /** * 现金 */ private BigDecimal cash; /** * 积分 */ private Integer point; /** * 获取结束时间 */ private Long endTime; } @Override public void addGoods(ShoppingCart shoppingCart) { @@ -108,4 +207,23 @@ shoppingCart.setAppUserId(userid); this.save(shoppingCart); } /** * 修改购物车数量 * @param setGoodsNumber * @return */ @Override public AjaxResult setGoodsNumber(SetGoodsNumber setGoodsNumber) { if(0 >= setGoodsNumber.getNumber()){ return AjaxResult.error("修改数量不能小于等于0"); } ShoppingCart shoppingCart = this.getById(setGoodsNumber.getId()); if(null != shoppingCart){ shoppingCart.setNumber(setGoodsNumber.getNumber()); this.updateById(shoppingCart); } return AjaxResult.success(); } } ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vo/SetGoodsNumber.java
@@ -11,7 +11,7 @@ @Data @ApiModel public class SetGoodsNumber { @ApiModelProperty(value = "商品id", required = true) @ApiModelProperty(value = "购物车数据id", required = true) private Integer id; @ApiModelProperty(value = "修改数量", required = true) private Integer number; ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/GoodsBargainPriceController.java
@@ -1,8 +1,19 @@ package com.ruoyi.other.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.GoodsBargainPrice; import com.ruoyi.other.api.domain.GoodsBargainPriceDetail; import com.ruoyi.other.api.vo.GetGoodsBargainPrice; import com.ruoyi.other.service.GoodsBargainPriceDetailService; import com.ruoyi.other.service.GoodsBargainPriceService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * <p> @@ -15,6 +26,33 @@ @RestController @RequestMapping("/goods-bargain-price") public class GoodsBargainPriceController { @Resource private GoodsBargainPriceService goodsBargainPriceService; @Resource private GoodsBargainPriceDetailService goodsBargainPriceDetailService; /** * 根据商品id和会员等级获取门店特价 * @param goodsBargainPrice * @return */ @PostMapping("/getGoodsBargainPrice") public R<GoodsBargainPriceDetail> getGoodsBargainPrice(@RequestBody GetGoodsBargainPrice goodsBargainPrice){ GoodsBargainPrice one = goodsBargainPriceService.getOne(new LambdaQueryWrapper<GoodsBargainPrice>().eq(GoodsBargainPrice::getGoodsId, goodsBargainPrice.getGoodsId()) .eq(GoodsBargainPrice::getShopId, goodsBargainPrice.getShopId()).eq(GoodsBargainPrice::getAuditStatus, 1).eq(GoodsBargainPrice::getDelFlag, 0) .orderByDesc(GoodsBargainPrice::getCreateTime).last(" limit 0,1")); if(null == one){ return R.ok(); } GoodsBargainPriceDetail detailServiceOne = goodsBargainPriceDetailService.getOne(new LambdaQueryWrapper<GoodsBargainPriceDetail>() .eq(GoodsBargainPriceDetail::getGoodsBargainPriceId, one.getId()).eq(GoodsBargainPriceDetail::getVip, goodsBargainPrice.getVip())); return R.ok(detailServiceOne); } } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/SeckillActivityInfoController.java
@@ -1,18 +1,26 @@ package com.ruoyi.other.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.other.api.domain.Goods; import com.ruoyi.other.api.domain.GoodsSeckill; import com.ruoyi.other.api.domain.SeckillActivityInfo; import com.ruoyi.other.api.vo.GetSeckillActivityInfo; import com.ruoyi.other.service.GoodsSeckillService; import com.ruoyi.other.service.SeckillActivityInfoService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; import java.util.List; /** * <p> @@ -28,6 +36,13 @@ public class SeckillActivityInfoController extends BaseController { @Resource private SeckillActivityInfoService seckillActivityInfoService; @Resource private GoodsSeckillService goodsSeckillService; /** * 秒杀活动列表 @@ -49,6 +64,26 @@ { return AjaxResult.success(seckillActivityInfoService.detail(id)); } /** * 根据商品id和会员等级获取对应的秒杀活动 * @param info * @return */ @PostMapping("/getSeckillActivityInfo") public R<GoodsSeckill> getSeckillActivityInfo(@RequestBody GetSeckillActivityInfo info){ SeckillActivityInfo one = seckillActivityInfoService.getOne(new LambdaQueryWrapper<SeckillActivityInfo>().eq(SeckillActivityInfo::getGoodId, info.getGoodsId()) .eq(SeckillActivityInfo::getDelFlag, 0).last(" and now() between start_time and end_time order by create_time limit 0,1")); if(null == one){ return R.ok(); } GoodsSeckill goodsSeckill = goodsSeckillService.getOne(new LambdaQueryWrapper<GoodsSeckill>().eq(GoodsSeckill::getSeckillActivityInfoId, one.getGoodId()).eq(GoodsSeckill::getVip, info.getVip())); if(null != goodsSeckill){ goodsSeckill.setEndTime(one.getEndTime().toEpochSecond(ZoneOffset.UTC) * 1000); } return R.ok(goodsSeckill); } }