From cfd292ef18e703e29ec88cf74c7f5488f42846fc Mon Sep 17 00:00:00 2001 From: chc <1501738723@qq.com> Date: Tue, 22 Nov 2022 17:20:17 +0800 Subject: [PATCH 01/18] =?UTF-8?q?=E8=87=AA=E6=8F=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lili/controller/order/CartController.java | 41 ++++++- .../store/StoreAddressBuyerController.java | 53 ++++++++ .../event/impl/DistributionOrderExecute.java | 3 +- .../event/impl/VerificationOrderExecute.java | 2 +- .../lili/event/impl/WechatMessageExecute.java | 1 + .../lili/common/swagger/Swagger2Config.java | 13 ++ .../member/serviceimpl/MemberServiceImpl.java | 4 +- .../order/cart/entity/dto/TradeDTO.java | 5 + .../cart/render/impl/CheckDataRender.java | 52 ++++---- .../cart/render/impl/SkuFreightRender.java | 116 ++++++++++-------- .../order/cart/service/CartService.java | 20 ++- .../order/cart/service/CartServiceImpl.java | 56 +++++++-- .../modules/order/order/entity/dos/Order.java | 27 +++- .../order/entity/enums/OrderStatusEnum.java | 1 + .../order/order/entity/vo/AllowOperation.java | 2 +- .../order/order/service/OrderService.java | 9 ++ .../order/serviceimpl/OrderServiceImpl.java | 31 ++++- .../order/serviceimpl/TradeServiceImpl.java | 2 +- .../entity/vo/StoreIndexStatisticsVO.java | 3 + .../IndexStatisticsServiceImpl.java | 3 +- .../lili/modules/store/entity/dos/Store.java | 3 + .../store/entity/dto/StoreSettingDTO.java | 3 + .../order/OrderStoreController.java | 10 ++ 23 files changed, 352 insertions(+), 108 deletions(-) create mode 100644 buyer-api/src/main/java/cn/lili/controller/store/StoreAddressBuyerController.java diff --git a/buyer-api/src/main/java/cn/lili/controller/order/CartController.java b/buyer-api/src/main/java/cn/lili/controller/order/CartController.java index f78e4d78..005a1c0c 100644 --- a/buyer-api/src/main/java/cn/lili/controller/order/CartController.java +++ b/buyer-api/src/main/java/cn/lili/controller/order/CartController.java @@ -189,20 +189,38 @@ public class CartController { } } + @ApiOperation(value = "选择自提地址") + @ApiImplicitParams({ + @ApiImplicitParam(name = "storeAddressId", value = "自提地址id ", required = true, paramType = "query"), + @ApiImplicitParam(name = "way", value = "购物车类型 ", paramType = "query") + }) + @GetMapping("/storeAddress") + public ResultMessage shippingSelfPickAddress(@NotNull(message = "自提地址ID不能为空") String storeAddressId, + String way) { + try { + cartService.shippingSelfAddress(storeAddressId, way); + return ResultUtil.success(); + } catch (ServiceException se) { + log.error(ResultCode.SHIPPING_NOT_APPLY.message(), se); + throw new ServiceException(ResultCode.SHIPPING_NOT_APPLY); + } catch (Exception e) { + log.error(ResultCode.CART_ERROR.message(), e); + throw new ServiceException(ResultCode.CART_ERROR); + } + } + @ApiOperation(value = "选择配送方式") @ApiImplicitParams({ @ApiImplicitParam(name = "shippingMethod", value = "配送方式:SELF_PICK_UP(自提)," + "LOCAL_TOWN_DELIVERY(同城配送)," + "LOGISTICS(物流) ", required = true, paramType = "query"), - @ApiImplicitParam(name = "selleId", value = "店铺id", paramType = "query"), @ApiImplicitParam(name = "way", value = "购物车类型 ", paramType = "query") }) - @GetMapping("/shippingMethod") + @PutMapping("/shippingMethod") public ResultMessage shippingMethod(@NotNull(message = "配送方式不能为空") String shippingMethod, - String selleId, String way) { try { - cartService.shippingMethod(selleId, shippingMethod, way); + cartService.shippingMethod( shippingMethod, way); return ResultUtil.success(); } catch (ServiceException se) { log.error(se.getMsg(), se); @@ -213,6 +231,21 @@ public class CartController { } } + @ApiOperation(value = "获取用户可选择的物流方式") + @ApiImplicitParams({ + @ApiImplicitParam(name = "way", value = "购物车类型 ", paramType = "query") + }) + @GetMapping("/shippingMethodList") + public ResultMessage shippingMethodList(String way) { + try { + return ResultUtil.data(cartService.shippingMethodList(way)); + } + catch (Exception e) { + e.printStackTrace(); + return ResultUtil.error(ResultCode.ERROR); + } + } + @ApiOperation(value = "选择发票") @ApiImplicitParams({ @ApiImplicitParam(name = "way", value = "购物车购买:CART/立即购买:BUY_NOW/拼团购买:PINTUAN / 积分购买:POINT ", required = true, paramType = "query"), diff --git a/buyer-api/src/main/java/cn/lili/controller/store/StoreAddressBuyerController.java b/buyer-api/src/main/java/cn/lili/controller/store/StoreAddressBuyerController.java new file mode 100644 index 00000000..a51acdf4 --- /dev/null +++ b/buyer-api/src/main/java/cn/lili/controller/store/StoreAddressBuyerController.java @@ -0,0 +1,53 @@ +package cn.lili.controller.store; + +import cn.lili.common.enums.ResultUtil; +import cn.lili.common.security.OperationalJudgment; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.PageVO; +import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.store.entity.dos.StoreAddress; +import cn.lili.modules.store.service.StoreAddressService; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +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 java.util.Objects; + +/** + * 买家端,商家地址(自提点)接口 + * + * @author chc + * @since 2022/6/2114:46 + */ +@RestController +@Api(tags = "买家端,商家地址(自提点)接口") +@RequestMapping("/buyer/store/address") +public class StoreAddressBuyerController { + + /** + * 店铺自提点 + */ + @Autowired + private StoreAddressService storeAddressService; + + @ApiOperation(value = "获取商家自提点分页") + @ApiImplicitParam(name = "storeId", value = "店铺Id", required = true, dataType = "String", paramType = "path") + @GetMapping("/page/{storeId}") + public ResultMessage> get(PageVO pageVo,@PathVariable String storeId) { + return ResultUtil.data(storeAddressService.getStoreAddress(storeId, pageVo)); + } + + @ApiOperation(value = "获取商家自提点信息") + @ApiImplicitParam(name = "id", value = "自提点ID", required = true, paramType = "path") + @GetMapping("/{id}") + public ResultMessage get(@PathVariable String id) { + StoreAddress address = OperationalJudgment.judgment(storeAddressService.getById(id)); + return ResultUtil.data(address); + } +} diff --git a/consumer/src/main/java/cn/lili/event/impl/DistributionOrderExecute.java b/consumer/src/main/java/cn/lili/event/impl/DistributionOrderExecute.java index 7b9f138a..4edd7f41 100644 --- a/consumer/src/main/java/cn/lili/event/impl/DistributionOrderExecute.java +++ b/consumer/src/main/java/cn/lili/event/impl/DistributionOrderExecute.java @@ -44,8 +44,9 @@ public class DistributionOrderExecute implements OrderStatusChangeEvent, EveryDa public void orderChange(OrderMessage orderMessage) { switch (orderMessage.getNewStatus()) { - //订单带校验/订单代发货,则记录分销信息 + //订单带校验/订单代发货/待自提,则记录分销信息 case TAKE: + case STAY_PICKED_UP: case UNDELIVERED: { //记录分销订单 distributionOrderService.calculationDistribution(orderMessage.getOrderSn()); diff --git a/consumer/src/main/java/cn/lili/event/impl/VerificationOrderExecute.java b/consumer/src/main/java/cn/lili/event/impl/VerificationOrderExecute.java index 008a2fc2..a0b50055 100644 --- a/consumer/src/main/java/cn/lili/event/impl/VerificationOrderExecute.java +++ b/consumer/src/main/java/cn/lili/event/impl/VerificationOrderExecute.java @@ -31,7 +31,7 @@ public class VerificationOrderExecute implements OrderStatusChangeEvent { @Override public void orderChange(OrderMessage orderMessage) { //订单状态为待核验,添加订单添加核验码 - if (orderMessage.getNewStatus().equals(OrderStatusEnum.TAKE)) { + if (orderMessage.getNewStatus().equals(OrderStatusEnum.TAKE) || orderMessage.getNewStatus().equals(OrderStatusEnum.STAY_PICKED_UP)) { //获取订单信息 Order order = orderService.getBySn(orderMessage.getOrderSn()); //获取随机数,判定是否存在 diff --git a/consumer/src/main/java/cn/lili/event/impl/WechatMessageExecute.java b/consumer/src/main/java/cn/lili/event/impl/WechatMessageExecute.java index cbab13e4..58fd2e27 100644 --- a/consumer/src/main/java/cn/lili/event/impl/WechatMessageExecute.java +++ b/consumer/src/main/java/cn/lili/event/impl/WechatMessageExecute.java @@ -42,6 +42,7 @@ public class WechatMessageExecute implements OrderStatusChangeEvent, TradeEvent case PAID: case UNDELIVERED: case DELIVERED: + case STAY_PICKED_UP: case COMPLETED: try { wechatMessageUtil.sendWechatMessage(orderMessage.getOrderSn()); diff --git a/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java b/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java index e604498b..3d92f8d5 100644 --- a/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java +++ b/framework/src/main/java/cn/lili/common/swagger/Swagger2Config.java @@ -81,6 +81,19 @@ public class Swagger2Config { .securitySchemes(securitySchemes()) .securityContexts(securityContexts()); } + @Bean + public Docket orderRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .groupName("订单") + .apiInfo(apiInfo()).select() + //扫描所有有注解的api,用这种方式更灵活 +// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + .apis(RequestHandlerSelectors.basePackage("cn.lili.controller.order")) + .paths(PathSelectors.any()) + .build() + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()); + } @Bean public Docket memberRestApi() { diff --git a/framework/src/main/java/cn/lili/modules/member/serviceimpl/MemberServiceImpl.java b/framework/src/main/java/cn/lili/modules/member/serviceimpl/MemberServiceImpl.java index a21b89ad..ec9f1ad3 100644 --- a/framework/src/main/java/cn/lili/modules/member/serviceimpl/MemberServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/member/serviceimpl/MemberServiceImpl.java @@ -41,6 +41,7 @@ import cn.lili.modules.store.entity.enums.StoreStatusEnum; import cn.lili.modules.store.service.StoreService; import cn.lili.mybatis.util.PageUtil; import cn.lili.rocketmq.tags.MemberTagsEnum; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; @@ -183,7 +184,8 @@ public class MemberServiceImpl extends ServiceImpl impleme @Override public Token usernameStoreLogin(String username, String password) { - Member member = this.findMember(username); +// Member member = this.findMember(username); + Member member = this.getOne(new LambdaQueryWrapper().eq(Member::getMobile,username)); //判断用户是否存在 if (member == null || !member.getDisabled()) { throw new ServiceException(ResultCode.USER_NOT_EXIST); diff --git a/framework/src/main/java/cn/lili/modules/order/cart/entity/dto/TradeDTO.java b/framework/src/main/java/cn/lili/modules/order/cart/entity/dto/TradeDTO.java index 45d9cd87..d522286e 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/entity/dto/TradeDTO.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/entity/dto/TradeDTO.java @@ -11,6 +11,7 @@ import cn.lili.modules.order.order.entity.vo.OrderVO; import cn.lili.modules.order.order.entity.vo.ReceiptVO; import cn.lili.modules.promotion.entity.dos.MemberCoupon; import cn.lili.modules.promotion.entity.vos.MemberCouponVO; +import cn.lili.modules.store.entity.dos.StoreAddress; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -106,6 +107,10 @@ public class TradeDTO implements Serializable { */ private MemberAddress memberAddress; + /** + * 自提地址 + */ + private StoreAddress storeAddress; /** * 客户端类型 diff --git a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/CheckDataRender.java b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/CheckDataRender.java index c85cfbbd..d1422a73 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/CheckDataRender.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/CheckDataRender.java @@ -155,35 +155,37 @@ public class CheckDataRender implements CartRenderStep { private void groupStore(TradeDTO tradeDTO) { //渲染的购物车 List cartList = new ArrayList<>(); - - //根据店铺分组 - Map> storeCollect = tradeDTO.getSkuList().stream().collect(Collectors.groupingBy(CartSkuVO::getStoreId)); - for (Map.Entry> storeCart : storeCollect.entrySet()) { - if (!storeCart.getValue().isEmpty()) { - CartVO cartVO = new CartVO(storeCart.getValue().get(0)); - if (CharSequenceUtil.isEmpty(cartVO.getDeliveryMethod())) { - cartVO.setDeliveryMethod(DeliveryMethodEnum.LOGISTICS.name()); - } - cartVO.setSkuList(storeCart.getValue()); - try { - //筛选属于当前店铺的优惠券 - storeCart.getValue().forEach(i -> i.getPromotionMap().forEach((key, value) -> { - if (key.contains(PromotionTypeEnum.COUPON.name())) { - JSONObject promotionsObj = JSONUtil.parseObj(value); - Coupon coupon = JSONUtil.toBean(promotionsObj, Coupon.class); - if (key.contains(PromotionTypeEnum.COUPON.name()) && coupon.getStoreId().equals(storeCart.getKey())) { - cartVO.getCanReceiveCoupon().add(new CouponVO(coupon)); + if(tradeDTO.getCartList() == null || tradeDTO.getCartList().size() == 0){ + //根据店铺分组 + Map> storeCollect = tradeDTO.getSkuList().stream().collect(Collectors.groupingBy(CartSkuVO::getStoreId)); + for (Map.Entry> storeCart : storeCollect.entrySet()) { + if (!storeCart.getValue().isEmpty()) { + CartVO cartVO = new CartVO(storeCart.getValue().get(0)); + if (CharSequenceUtil.isEmpty(cartVO.getDeliveryMethod())) { + cartVO.setDeliveryMethod(DeliveryMethodEnum.LOGISTICS.name()); + } + cartVO.setSkuList(storeCart.getValue()); + try { + //筛选属于当前店铺的优惠券 + storeCart.getValue().forEach(i -> i.getPromotionMap().forEach((key, value) -> { + if (key.contains(PromotionTypeEnum.COUPON.name())) { + JSONObject promotionsObj = JSONUtil.parseObj(value); + Coupon coupon = JSONUtil.toBean(promotionsObj, Coupon.class); + if (key.contains(PromotionTypeEnum.COUPON.name()) && coupon.getStoreId().equals(storeCart.getKey())) { + cartVO.getCanReceiveCoupon().add(new CouponVO(coupon)); + } } - } - })); - } catch (Exception e) { - log.error("筛选属于当前店铺的优惠券发生异常!", e); + })); + } catch (Exception e) { + log.error("筛选属于当前店铺的优惠券发生异常!", e); + } + storeCart.getValue().stream().filter(i -> Boolean.TRUE.equals(i.getChecked())).findFirst().ifPresent(cartSkuVO -> cartVO.setChecked(true)); + cartList.add(cartVO); } - storeCart.getValue().stream().filter(i -> Boolean.TRUE.equals(i.getChecked())).findFirst().ifPresent(cartSkuVO -> cartVO.setChecked(true)); - cartList.add(cartVO); } + tradeDTO.setCartList(cartList); } - tradeDTO.setCartList(cartList); + } /** diff --git a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/SkuFreightRender.java b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/SkuFreightRender.java index 799c62b8..a25fef51 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/SkuFreightRender.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/SkuFreightRender.java @@ -3,10 +3,12 @@ package cn.lili.modules.order.cart.render.impl; import cn.lili.common.utils.CurrencyUtil; import cn.lili.modules.member.entity.dos.MemberAddress; import cn.lili.modules.order.cart.entity.dto.TradeDTO; +import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum; import cn.lili.modules.order.cart.entity.enums.RenderStepEnums; import cn.lili.modules.order.cart.entity.vo.CartSkuVO; import cn.lili.modules.order.cart.render.CartRenderStep; import cn.lili.modules.store.entity.dos.FreightTemplateChild; +import cn.lili.modules.store.entity.dos.StoreAddress; import cn.lili.modules.store.entity.dto.FreightTemplateChildDTO; import cn.lili.modules.store.entity.enums.FreightTemplateEnum; import cn.lili.modules.store.entity.vos.FreightTemplateVO; @@ -42,71 +44,77 @@ public class SkuFreightRender implements CartRenderStep { List cartSkuVOS = tradeDTO.getCheckedSkuList(); //会员收货地址问题处理 MemberAddress memberAddress = tradeDTO.getMemberAddress(); + StoreAddress storeAddress = tradeDTO.getStoreAddress(); //如果收货地址为空,则抛出异常 - if (memberAddress == null) { + if (memberAddress == null && storeAddress == null) { return; } - //运费分组信息 - Map> freightGroups = freightTemplateGrouping(cartSkuVOS); + //选择物流的时候计算价格 + if(DeliveryMethodEnum.LOGISTICS.name().equals(tradeDTO.getCartList().get(0).getDeliveryMethod())){ + if (memberAddress != null) { + //运费分组信息 + Map> freightGroups = freightTemplateGrouping(cartSkuVOS); - //循环运费模版 - for (Map.Entry> freightTemplateGroup : freightGroups.entrySet()) { + //循环运费模版 + for (Map.Entry> freightTemplateGroup : freightGroups.entrySet()) { - //商品id列表 - List skuIds = freightTemplateGroup.getValue(); + //商品id列表 + List skuIds = freightTemplateGroup.getValue(); - //当前购物车商品列表 - List currentCartSkus = cartSkuVOS.stream().filter(item -> skuIds.contains(item.getGoodsSku().getId())).collect(Collectors.toList()); + //当前购物车商品列表 + List currentCartSkus = cartSkuVOS.stream().filter(item -> skuIds.contains(item.getGoodsSku().getId())).collect(Collectors.toList()); - //寻找对应对商品运费计算模版 - FreightTemplateVO freightTemplate = freightTemplateService.getFreightTemplate(freightTemplateGroup.getKey()); - if (freightTemplate != null - && freightTemplate.getFreightTemplateChildList() != null - && !freightTemplate.getFreightTemplateChildList().isEmpty()) { - //店铺模版免运费则跳过 - if (freightTemplate.getPricingMethod().equals(FreightTemplateEnum.FREE.name())) { - break; - } + //寻找对应对商品运费计算模版 + FreightTemplateVO freightTemplate = freightTemplateService.getFreightTemplate(freightTemplateGroup.getKey()); + if (freightTemplate != null + && freightTemplate.getFreightTemplateChildList() != null + && !freightTemplate.getFreightTemplateChildList().isEmpty()) { + //店铺模版免运费则跳过 + if (freightTemplate.getPricingMethod().equals(FreightTemplateEnum.FREE.name())) { + break; + } - //运费模版 - FreightTemplateChild freightTemplateChild = null; + //运费模版 + FreightTemplateChild freightTemplateChild = null; - //获取市级别id匹配运费模版 - String addressId = memberAddress.getConsigneeAddressIdPath().split(",")[1]; - for (FreightTemplateChild templateChild : freightTemplate.getFreightTemplateChildList()) { - //模版匹配判定 - if (templateChild.getAreaId().contains(addressId)) { - freightTemplateChild = templateChild; - break; + //获取市级别id匹配运费模版 + String addressId = memberAddress.getConsigneeAddressIdPath().split(",")[1]; + for (FreightTemplateChild templateChild : freightTemplate.getFreightTemplateChildList()) { + //模版匹配判定 + if (templateChild.getAreaId().contains(addressId)) { + freightTemplateChild = templateChild; + break; + } + } + //如果没有匹配到物流规则,则说明不支持配送 + if (freightTemplateChild == null) { + if (tradeDTO.getNotSupportFreight() == null) { + tradeDTO.setNotSupportFreight(new ArrayList<>()); + } + tradeDTO.getNotSupportFreight().addAll(currentCartSkus); + continue; + } + + //物流规则模型创立 + FreightTemplateChildDTO freightTemplateChildDTO = new FreightTemplateChildDTO(freightTemplateChild); + //模型写入运费模版设置的计费方式 + freightTemplateChildDTO.setPricingMethod(freightTemplate.getPricingMethod()); + + //计算运费总数 + Double count = currentCartSkus.stream().mapToDouble(item -> + // 根据计费规则 累加计费基数 + freightTemplateChildDTO.getPricingMethod().equals(FreightTemplateEnum.NUM.name()) ? + item.getNum().doubleValue() : + CurrencyUtil.mul(item.getNum(), item.getGoodsSku().getWeight()) + ).sum(); + + //计算运费 + Double countFreight = countFreight(count, freightTemplateChildDTO); + + //写入SKU运费 + resetFreightPrice(FreightTemplateEnum.valueOf(freightTemplateChildDTO.getPricingMethod()), count, countFreight, currentCartSkus); } } - //如果没有匹配到物流规则,则说明不支持配送 - if (freightTemplateChild == null) { - if (tradeDTO.getNotSupportFreight() == null) { - tradeDTO.setNotSupportFreight(new ArrayList<>()); - } - tradeDTO.getNotSupportFreight().addAll(currentCartSkus); - continue; - } - - //物流规则模型创立 - FreightTemplateChildDTO freightTemplateChildDTO = new FreightTemplateChildDTO(freightTemplateChild); - //模型写入运费模版设置的计费方式 - freightTemplateChildDTO.setPricingMethod(freightTemplate.getPricingMethod()); - - //计算运费总数 - Double count = currentCartSkus.stream().mapToDouble(item -> - // 根据计费规则 累加计费基数 - freightTemplateChildDTO.getPricingMethod().equals(FreightTemplateEnum.NUM.name()) ? - item.getNum().doubleValue() : - CurrencyUtil.mul(item.getNum(), item.getGoodsSku().getWeight()) - ).sum(); - - //计算运费 - Double countFreight = countFreight(count, freightTemplateChildDTO); - - //写入SKU运费 - resetFreightPrice(FreightTemplateEnum.valueOf(freightTemplateChildDTO.getPricingMethod()), count, countFreight, currentCartSkus); } } } diff --git a/framework/src/main/java/cn/lili/modules/order/cart/service/CartService.java b/framework/src/main/java/cn/lili/modules/order/cart/service/CartService.java index d11d8aa8..2d525af4 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/service/CartService.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/service/CartService.java @@ -7,6 +7,8 @@ import cn.lili.modules.order.cart.entity.vo.TradeParams; import cn.lili.modules.order.order.entity.dos.Trade; import cn.lili.modules.order.order.entity.vo.ReceiptVO; +import java.util.List; + /** * 购物车业务层 * @@ -111,6 +113,14 @@ public interface CartService { */ void shippingAddress(String shippingAddressId, String way); + /** + * 选择自提地址 + * + * @param shopAddressId 收货地址id + * @param way 购物车类型 + */ + void shippingSelfAddress(String shopAddressId, String way); + /** * 选择发票 * @@ -123,11 +133,10 @@ public interface CartService { /** * 选择配送方式 * - * @param storeId 店铺id * @param deliveryMethod 配送方式 * @param way 购物车类型 */ - void shippingMethod(String storeId, String deliveryMethod, String way); + void shippingMethod(String deliveryMethod, String way); /** * 获取购物车商品数量 @@ -160,4 +169,11 @@ public interface CartService { * @return 交易信息 */ Trade createTrade(TradeParams tradeParams); + + /*** + * 获取可使用的配送方式 + * @param way + * @return + */ + List shippingMethodList(String way); } diff --git a/framework/src/main/java/cn/lili/modules/order/cart/service/CartServiceImpl.java b/framework/src/main/java/cn/lili/modules/order/cart/service/CartServiceImpl.java index 485bb249..c0970787 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/service/CartServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/service/CartServiceImpl.java @@ -46,6 +46,10 @@ import cn.lili.modules.promotion.service.PointsGoodsService; import cn.lili.modules.promotion.service.PromotionGoodsService; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.service.EsGoodsSearchService; +import cn.lili.modules.store.entity.dos.Store; +import cn.lili.modules.store.entity.dos.StoreAddress; +import cn.lili.modules.store.service.StoreAddressService; +import cn.lili.modules.store.service.StoreService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -116,6 +120,12 @@ public class CartServiceImpl implements CartService { @Autowired private WholesaleService wholesaleService; + @Autowired + private StoreService storeService; + + @Autowired + private StoreAddressService storeAddressService; + @Override public void add(String skuId, Integer num, String cartType, Boolean cover) { AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser()); @@ -438,6 +448,20 @@ public class CartServiceImpl implements CartService { this.resetTradeDTO(tradeDTO); } + @Override + public void shippingSelfAddress(String shopAddressId, String way) { + //默认购物车 + CartTypeEnum cartTypeEnum = CartTypeEnum.CART; + if (CharSequenceUtil.isNotEmpty(way)) { + cartTypeEnum = CartTypeEnum.valueOf(way); + } + + TradeDTO tradeDTO = this.readDTO(cartTypeEnum); + StoreAddress storeAddress = storeAddressService.getById(shopAddressId); + tradeDTO.setStoreAddress(storeAddress); + this.resetTradeDTO(tradeDTO); + } + /** * 选择发票 * @@ -459,23 +483,21 @@ public class CartServiceImpl implements CartService { /** * 选择配送方式 * - * @param storeId 店铺id * @param deliveryMethod 配送方式 * @param way 购物车类型 */ @Override - public void shippingMethod(String storeId, String deliveryMethod, String way) { + public void shippingMethod(String deliveryMethod, String way) { CartTypeEnum cartTypeEnum = CartTypeEnum.CART; if (CharSequenceUtil.isNotEmpty(way)) { cartTypeEnum = CartTypeEnum.valueOf(way); } - TradeDTO tradeDTO = this.readDTO(cartTypeEnum); + TradeDTO tradeDTO = this.getCheckedTradeDTO(cartTypeEnum); for (CartVO cartVO : tradeDTO.getCartList()) { - if (cartVO.getStoreId().equals(storeId)) { - cartVO.setDeliveryMethod(DeliveryMethodEnum.valueOf(deliveryMethod).name()); - } + cartVO.setDeliveryMethod(DeliveryMethodEnum.valueOf(deliveryMethod).name()); } this.resetTradeDTO(tradeDTO); + TradeDTO neTradeDTO = (TradeDTO) cache.get(this.getOriginKey(cartTypeEnum)); } /** @@ -547,8 +569,10 @@ public class CartServiceImpl implements CartService { tradeDTO.setStoreRemark(tradeParams.getRemark()); tradeDTO.setParentOrderSn(tradeParams.getParentOrderSn()); //订单无收货地址校验 - if (tradeDTO.getMemberAddress() == null) { - throw new ServiceException(ResultCode.MEMBER_ADDRESS_NOT_EXIST); + if(tradeDTO.getStoreAddress() == null){ + if (tradeDTO.getMemberAddress() == null) { + throw new ServiceException(ResultCode.MEMBER_ADDRESS_NOT_EXIST); + } } //构建交易 Trade trade = tradeBuilder.createTrade(tradeDTO); @@ -556,6 +580,22 @@ public class CartServiceImpl implements CartService { return trade; } + @Override + public List shippingMethodList(String way) { + List list = new ArrayList(); + list.add(DeliveryMethodEnum.LOGISTICS.name()); + TradeDTO tradeDTO = this.getCheckedTradeDTO(CartTypeEnum.valueOf(way)); + if(tradeDTO.getCartList().size()==1){ + for (CartVO cartVO : tradeDTO.getCartList()) { + Store store = storeService.getById(cartVO.getStoreId()); + if(store.getSelfPickFlag() != null && store.getSelfPickFlag()){ + list.add(DeliveryMethodEnum.SELF_PICK_UP.name()); + } + } + } + return list; + } + /** * 获取购物车类型 diff --git a/framework/src/main/java/cn/lili/modules/order/order/entity/dos/Order.java b/framework/src/main/java/cn/lili/modules/order/order/entity/dos/Order.java index f185d17d..a937e125 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/entity/dos/Order.java +++ b/framework/src/main/java/cn/lili/modules/order/order/entity/dos/Order.java @@ -210,6 +210,15 @@ public class Order extends BaseEntity { @ApiModelProperty(value = "qrCode 实物为提货码 虚拟货物为账号") private String qrCode; + @ApiModelProperty(value = "自提点地址") + private String storeAddressPath; + + @ApiModelProperty(value = "自提点电话") + private String storeAddressMobile; + + @ApiModelProperty(value = "自提点地址经纬度") + private String storeAddressCenter; + /** * 构建订单 * @@ -233,11 +242,19 @@ public class Order extends BaseEntity { this.setRemark(cartVO.getRemark()); this.setFreightPrice(tradeDTO.getPriceDetailDTO().getFreightPrice()); //会员收件信息 - this.setConsigneeAddressIdPath(tradeDTO.getMemberAddress().getConsigneeAddressIdPath()); - this.setConsigneeAddressPath(tradeDTO.getMemberAddress().getConsigneeAddressPath()); - this.setConsigneeDetail(tradeDTO.getMemberAddress().getDetail()); - this.setConsigneeMobile(tradeDTO.getMemberAddress().getMobile()); - this.setConsigneeName(tradeDTO.getMemberAddress().getName()); + if(DeliveryMethodEnum.LOGISTICS.name().equals(cartVO.getDeliveryMethod())){ + this.setConsigneeAddressIdPath(tradeDTO.getMemberAddress().getConsigneeAddressIdPath()); + this.setConsigneeAddressPath(tradeDTO.getMemberAddress().getConsigneeAddressPath()); + this.setConsigneeDetail(tradeDTO.getMemberAddress().getDetail()); + this.setConsigneeMobile(tradeDTO.getMemberAddress().getMobile()); + this.setConsigneeName(tradeDTO.getMemberAddress().getName()); + } + //自提点信息 + if(DeliveryMethodEnum.SELF_PICK_UP.name().equals(cartVO.getDeliveryMethod())){ + this.setStoreAddressPath(tradeDTO.getStoreAddress().getAddress()); + this.setStoreAddressMobile(tradeDTO.getStoreAddress().getMobile()); + this.setStoreAddressCenter(tradeDTO.getStoreAddress().getCenter()); + } //平台优惠券判定 if (tradeDTO.getPlatformCoupon() != null) { this.setUsePlatformMemberCouponId(tradeDTO.getPlatformCoupon().getMemberCoupon().getId()); diff --git a/framework/src/main/java/cn/lili/modules/order/order/entity/enums/OrderStatusEnum.java b/framework/src/main/java/cn/lili/modules/order/order/entity/enums/OrderStatusEnum.java index 6d9f4906..8edcaccf 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/entity/enums/OrderStatusEnum.java +++ b/framework/src/main/java/cn/lili/modules/order/order/entity/enums/OrderStatusEnum.java @@ -16,6 +16,7 @@ public enum OrderStatusEnum { UNDELIVERED("待发货"), DELIVERED("已发货"), COMPLETED("已完成"), + STAY_PICKED_UP("待自提"), /** * 虚拟订单需要核验商品 */ diff --git a/framework/src/main/java/cn/lili/modules/order/order/entity/vo/AllowOperation.java b/framework/src/main/java/cn/lili/modules/order/order/entity/vo/AllowOperation.java index 6ef7ca59..dd480e32 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/entity/vo/AllowOperation.java +++ b/framework/src/main/java/cn/lili/modules/order/order/entity/vo/AllowOperation.java @@ -63,7 +63,7 @@ public class AllowOperation implements Serializable { } //新订单 - if (CharSequenceUtil.equalsAny(status, OrderStatusEnum.UNPAID.name(), OrderStatusEnum.PAID.name(), OrderStatusEnum.UNDELIVERED.name())) { + if (CharSequenceUtil.equalsAny(status, OrderStatusEnum.UNPAID.name(), OrderStatusEnum.PAID.name(), OrderStatusEnum.UNDELIVERED.name(), OrderStatusEnum.STAY_PICKED_UP.name())) { this.cancel = true; } //新订单,允许支付 diff --git a/framework/src/main/java/cn/lili/modules/order/order/service/OrderService.java b/framework/src/main/java/cn/lili/modules/order/order/service/OrderService.java index 3740bb08..507d797f 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/service/OrderService.java +++ b/framework/src/main/java/cn/lili/modules/order/order/service/OrderService.java @@ -183,6 +183,15 @@ public interface OrderService extends IService { */ Order take(String orderSn, String verificationCode); + + /** + * 订单核验 + * + * @param verificationCode 验证码 + * @return 订单 + */ + Order take(String verificationCode); + /** * 根据核验码获取订单信息 * diff --git a/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java b/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java index 757b2a95..9ecb22ac 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/OrderServiceImpl.java @@ -16,10 +16,12 @@ import cn.lili.common.properties.RocketmqCustomProperties; import cn.lili.common.security.OperationalJudgment; import cn.lili.common.security.context.UserContext; import cn.lili.common.security.enums.UserEnums; +import cn.lili.common.utils.ObjectUtil; import cn.lili.common.utils.SnowFlake; import cn.lili.modules.goods.entity.dto.GoodsCompleteMessage; import cn.lili.modules.member.entity.dto.MemberAddressDTO; import cn.lili.modules.order.cart.entity.dto.TradeDTO; +import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum; import cn.lili.modules.order.order.aop.OrderLogPoint; import cn.lili.modules.order.order.entity.dos.*; import cn.lili.modules.order.order.entity.dto.OrderBatchDeliverDTO; @@ -290,12 +292,13 @@ public class OrderServiceImpl extends ServiceImpl implements Order order = OperationalJudgment.judgment(this.getBySn(orderSn)); //如果订单促销类型不为空&&订单是拼团订单,并且订单未成团,则抛出异常 if (OrderPromotionTypeEnum.PINTUAN.name().equals(order.getOrderPromotionType()) - && !order.getOrderStatus().equals(OrderStatusEnum.UNDELIVERED.name())) { + && !CharSequenceUtil.equalsAny(order.getOrderStatus(),OrderStatusEnum.UNDELIVERED.name(),OrderStatusEnum.STAY_PICKED_UP.name())) { throw new ServiceException(ResultCode.ORDER_CAN_NOT_CANCEL); } if (CharSequenceUtil.equalsAny(order.getOrderStatus(), OrderStatusEnum.UNDELIVERED.name(), OrderStatusEnum.UNPAID.name(), + OrderStatusEnum.STAY_PICKED_UP.name(), OrderStatusEnum.PAID.name())) { order.setOrderStatus(OrderStatusEnum.CANCELLED.name()); @@ -472,11 +475,24 @@ public class OrderServiceImpl extends ServiceImpl implements return order; } + @Override + public Order take(String verificationCode) { + String storeId = OperationalJudgment.judgment(UserContext.getCurrentUser()).getStoreId(); + Order order = this.getOne(new LambdaQueryWrapper().eq(Order::getVerificationCode, verificationCode).eq(Order::getStoreId, storeId)); + if(order == null){ + throw new ServiceException(ResultCode.ORDER_NOT_EXIST); + } + order.setOrderStatus(OrderStatusEnum.COMPLETED.name()); + //订单完成 + this.complete(order.getSn()); + return order; + } + @Override public Order getOrderByVerificationCode(String verificationCode) { String storeId = Objects.requireNonNull(UserContext.getCurrentUser()).getStoreId(); return this.getOne(new LambdaQueryWrapper() - .eq(Order::getOrderStatus, OrderStatusEnum.TAKE.name()) + .in(Order::getOrderStatus, OrderStatusEnum.TAKE.name(),OrderStatusEnum.STAY_PICKED_UP.name()) .eq(Order::getStoreId, storeId) .eq(Order::getVerificationCode, verificationCode)); } @@ -938,13 +954,20 @@ public class OrderServiceImpl extends ServiceImpl implements */ @Transactional(rollbackFor = Exception.class) public void normalOrderConfirm(String orderSn) { + OrderStatusEnum orderStatusEnum = null; + Order order = this.getBySn(orderSn); + if(DeliveryMethodEnum.SELF_PICK_UP.name().equals(order.getDeliveryMethod())){ + orderStatusEnum = OrderStatusEnum.STAY_PICKED_UP; + }else if (DeliveryMethodEnum.LOGISTICS.name().equals(order.getDeliveryMethod())){ + orderStatusEnum = OrderStatusEnum.UNDELIVERED; + } //修改订单 this.update(new LambdaUpdateWrapper() .eq(Order::getSn, orderSn) - .set(Order::getOrderStatus, OrderStatusEnum.UNDELIVERED.name())); + .set(Order::getOrderStatus, orderStatusEnum.name())); //修改订单 OrderMessage orderMessage = new OrderMessage(); - orderMessage.setNewStatus(OrderStatusEnum.UNDELIVERED); + orderMessage.setNewStatus(orderStatusEnum); orderMessage.setOrderSn(orderSn); this.sendUpdateStatusMessage(orderMessage); } diff --git a/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/TradeServiceImpl.java b/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/TradeServiceImpl.java index 6094598d..199eaf65 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/TradeServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/order/order/serviceimpl/TradeServiceImpl.java @@ -1 +1 @@ -package cn.lili.modules.order.order.serviceimpl; import cn.hutool.json.JSONUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.properties.RocketmqCustomProperties; import cn.lili.modules.member.entity.dos.MemberAddress; import cn.lili.modules.member.entity.enums.PointTypeEnum; import cn.lili.modules.member.service.MemberService; import cn.lili.modules.order.cart.entity.dto.MemberCouponDTO; import cn.lili.modules.order.cart.entity.dto.TradeDTO; import cn.lili.modules.order.cart.entity.enums.CartTypeEnum; import cn.lili.modules.order.cart.entity.vo.CartVO; import cn.lili.modules.order.order.entity.dos.Order; import cn.lili.modules.order.order.entity.dos.Trade; import cn.lili.modules.order.order.entity.enums.PayStatusEnum; import cn.lili.modules.order.order.mapper.TradeMapper; import cn.lili.modules.order.order.service.OrderService; import cn.lili.modules.order.order.service.TradeService; import cn.lili.modules.promotion.service.CouponService; import cn.lili.modules.promotion.service.KanjiaActivityService; import cn.lili.modules.promotion.service.MemberCouponService; import cn.lili.rocketmq.RocketmqSendCallbackBuilder; import cn.lili.rocketmq.tags.OrderTagsEnum; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; /** * 交易业务层实现 * * @author Chopper * @since 2020/11/17 7:39 下午 */ @Service public class TradeServiceImpl extends ServiceImpl implements TradeService { /** * 缓存 */ @Autowired private Cache cache; /** * 订单 */ @Autowired private OrderService orderService; /** * 会员 */ @Autowired private MemberService memberService; /** * 优惠券 */ @Autowired private CouponService couponService; /** * 会员优惠券 */ @Autowired private MemberCouponService memberCouponService; /** * 砍价 */ @Autowired private KanjiaActivityService kanjiaActivityService; /** * RocketMQ */ @Autowired private RocketMQTemplate rocketMQTemplate; /** * RocketMQ 配置 */ @Autowired private RocketmqCustomProperties rocketmqCustomProperties; @Override @Transactional(rollbackFor = Exception.class) public Trade createTrade(TradeDTO tradeDTO) { //创建订单预校验 createTradeCheck(tradeDTO); Trade trade = new Trade(tradeDTO); String key = CachePrefix.TRADE.getPrefix() + trade.getSn(); //优惠券预处理 couponPretreatment(tradeDTO); //积分预处理 pointPretreatment(tradeDTO); //添加交易 this.save(trade); //添加订单 orderService.intoDB(tradeDTO); //砍价订单处理 kanjiaPretreatment(tradeDTO); //写入缓存,给消费者调用 cache.put(key, JSONUtil.toJsonStr(tradeDTO)); //构建订单创建消息 String destination = rocketmqCustomProperties.getOrderTopic() + ":" + OrderTagsEnum.ORDER_CREATE.name(); //发送订单创建消息 rocketMQTemplate.asyncSend(destination, key, RocketmqSendCallbackBuilder.commonCallback()); return trade; } /** * 创建订单最后一步校验 * * @param tradeDTO 购物车视图 */ private void createTradeCheck(TradeDTO tradeDTO) { //创建订单如果没有收获地址, MemberAddress memberAddress = tradeDTO.getMemberAddress(); if (memberAddress == null) { throw new ServiceException(ResultCode.MEMBER_ADDRESS_NOT_EXIST); } //订单配送区域校验 if (tradeDTO.getNotSupportFreight() != null && !tradeDTO.getNotSupportFreight().isEmpty()) { StringBuilder stringBuilder = new StringBuilder("包含商品有-"); tradeDTO.getNotSupportFreight().forEach(sku -> stringBuilder.append(sku.getGoodsSku().getGoodsName())); throw new ServiceException(ResultCode.ORDER_NOT_SUPPORT_DISTRIBUTION, stringBuilder.toString()); } if (tradeDTO.getCartList().stream().noneMatch(CartVO::getChecked)) { throw new ServiceException(ResultCode.ORDER_NOT_EXIST_VALID); } } @Override public Trade getBySn(String sn) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Trade::getSn, sn); return this.getOne(queryWrapper); } @Override @Transactional(rollbackFor = Exception.class) public void payTrade(String tradeSn, String paymentName, String receivableNo) { LambdaQueryWrapper orderQueryWrapper = new LambdaQueryWrapper<>(); orderQueryWrapper.eq(Order::getTradeSn, tradeSn); List orders = orderService.list(orderQueryWrapper); for (Order order : orders) { orderService.payOrder(order.getSn(), paymentName, receivableNo); } Trade trade = this.getBySn(tradeSn); trade.setPayStatus(PayStatusEnum.PAID.name()); this.saveOrUpdate(trade); } /** * 优惠券预处理 * 下单同时,扣除优惠券 * * @param tradeDTO 购物车视图 */ private void couponPretreatment(TradeDTO tradeDTO) { List memberCouponDTOList = new ArrayList<>(); if (null != tradeDTO.getPlatformCoupon()) { memberCouponDTOList.add(tradeDTO.getPlatformCoupon()); } Collection storeCoupons = tradeDTO.getStoreCoupons().values(); if (!storeCoupons.isEmpty()) { memberCouponDTOList.addAll(storeCoupons); } List ids = memberCouponDTOList.stream().map(e -> e.getMemberCoupon().getId()).collect(Collectors.toList()); memberCouponService.used(tradeDTO.getMemberId(), ids); memberCouponDTOList.forEach(e -> couponService.usedCoupon(e.getMemberCoupon().getCouponId(), 1)); } /** * 创建交易,积分处理 * * @param tradeDTO 购物车视图 */ private void pointPretreatment(TradeDTO tradeDTO) { //需要支付积分 if (tradeDTO.getPriceDetailDTO() != null && tradeDTO.getPriceDetailDTO().getPayPoint() != null && tradeDTO.getPriceDetailDTO().getPayPoint() > 0) { StringBuilder orderSns = new StringBuilder(); for (CartVO item : tradeDTO.getCartList()) { orderSns.append(item.getSn()); } boolean result = memberService.updateMemberPoint(tradeDTO.getPriceDetailDTO().getPayPoint(), PointTypeEnum.REDUCE.name(), tradeDTO.getMemberId(), "订单【" + orderSns + "】创建,积分扣减"); if (!result) { throw new ServiceException(ResultCode.PAY_POINT_ENOUGH); } } } /** * 创建交易、砍价处理 * * @param tradeDTO 购物车视图 */ private void kanjiaPretreatment(TradeDTO tradeDTO) { if (tradeDTO.getCartTypeEnum().equals(CartTypeEnum.KANJIA)) { String kanjiaId = tradeDTO.getSkuList().get(0).getKanjiaId(); kanjiaActivityService.endKanjiaActivity(kanjiaId); } } } \ No newline at end of file +package cn.lili.modules.order.order.serviceimpl; import cn.hutool.json.JSONUtil; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.properties.RocketmqCustomProperties; import cn.lili.modules.member.entity.dos.MemberAddress; import cn.lili.modules.member.entity.enums.PointTypeEnum; import cn.lili.modules.member.service.MemberService; import cn.lili.modules.order.cart.entity.dto.MemberCouponDTO; import cn.lili.modules.order.cart.entity.dto.TradeDTO; import cn.lili.modules.order.cart.entity.enums.CartTypeEnum; import cn.lili.modules.order.cart.entity.vo.CartVO; import cn.lili.modules.order.order.entity.dos.Order; import cn.lili.modules.order.order.entity.dos.Trade; import cn.lili.modules.order.order.entity.enums.PayStatusEnum; import cn.lili.modules.order.order.mapper.TradeMapper; import cn.lili.modules.order.order.service.OrderService; import cn.lili.modules.order.order.service.TradeService; import cn.lili.modules.promotion.service.CouponService; import cn.lili.modules.promotion.service.KanjiaActivityService; import cn.lili.modules.promotion.service.MemberCouponService; import cn.lili.rocketmq.RocketmqSendCallbackBuilder; import cn.lili.rocketmq.tags.OrderTagsEnum; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; /** * 交易业务层实现 * * @author Chopper * @since 2020/11/17 7:39 下午 */ @Service public class TradeServiceImpl extends ServiceImpl implements TradeService { /** * 缓存 */ @Autowired private Cache cache; /** * 订单 */ @Autowired private OrderService orderService; /** * 会员 */ @Autowired private MemberService memberService; /** * 优惠券 */ @Autowired private CouponService couponService; /** * 会员优惠券 */ @Autowired private MemberCouponService memberCouponService; /** * 砍价 */ @Autowired private KanjiaActivityService kanjiaActivityService; /** * RocketMQ */ @Autowired private RocketMQTemplate rocketMQTemplate; /** * RocketMQ 配置 */ @Autowired private RocketmqCustomProperties rocketmqCustomProperties; @Override @Transactional(rollbackFor = Exception.class) public Trade createTrade(TradeDTO tradeDTO) { //创建订单预校验 createTradeCheck(tradeDTO); Trade trade = new Trade(tradeDTO); String key = CachePrefix.TRADE.getPrefix() + trade.getSn(); //优惠券预处理 couponPretreatment(tradeDTO); //积分预处理 pointPretreatment(tradeDTO); //添加交易 this.save(trade); //添加订单 orderService.intoDB(tradeDTO); //砍价订单处理 kanjiaPretreatment(tradeDTO); //写入缓存,给消费者调用 cache.put(key, JSONUtil.toJsonStr(tradeDTO)); //构建订单创建消息 String destination = rocketmqCustomProperties.getOrderTopic() + ":" + OrderTagsEnum.ORDER_CREATE.name(); //发送订单创建消息 rocketMQTemplate.asyncSend(destination, key, RocketmqSendCallbackBuilder.commonCallback()); return trade; } /** * 创建订单最后一步校验 * * @param tradeDTO 购物车视图 */ private void createTradeCheck(TradeDTO tradeDTO) { if(tradeDTO.getStoreAddress() == null){ //创建订单如果没有收获地址, MemberAddress memberAddress = tradeDTO.getMemberAddress(); if (memberAddress == null) { throw new ServiceException(ResultCode.MEMBER_ADDRESS_NOT_EXIST); } //订单配送区域校验 if (tradeDTO.getNotSupportFreight() != null && !tradeDTO.getNotSupportFreight().isEmpty()) { StringBuilder stringBuilder = new StringBuilder("包含商品有-"); tradeDTO.getNotSupportFreight().forEach(sku -> stringBuilder.append(sku.getGoodsSku().getGoodsName())); throw new ServiceException(ResultCode.ORDER_NOT_SUPPORT_DISTRIBUTION, stringBuilder.toString()); } if (tradeDTO.getCartList().stream().noneMatch(CartVO::getChecked)) { throw new ServiceException(ResultCode.ORDER_NOT_EXIST_VALID); } } } @Override public Trade getBySn(String sn) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Trade::getSn, sn); return this.getOne(queryWrapper); } @Override @Transactional(rollbackFor = Exception.class) public void payTrade(String tradeSn, String paymentName, String receivableNo) { LambdaQueryWrapper orderQueryWrapper = new LambdaQueryWrapper<>(); orderQueryWrapper.eq(Order::getTradeSn, tradeSn); List orders = orderService.list(orderQueryWrapper); for (Order order : orders) { orderService.payOrder(order.getSn(), paymentName, receivableNo); } Trade trade = this.getBySn(tradeSn); trade.setPayStatus(PayStatusEnum.PAID.name()); this.saveOrUpdate(trade); } /** * 优惠券预处理 * 下单同时,扣除优惠券 * * @param tradeDTO 购物车视图 */ private void couponPretreatment(TradeDTO tradeDTO) { List memberCouponDTOList = new ArrayList<>(); if (null != tradeDTO.getPlatformCoupon()) { memberCouponDTOList.add(tradeDTO.getPlatformCoupon()); } Collection storeCoupons = tradeDTO.getStoreCoupons().values(); if (!storeCoupons.isEmpty()) { memberCouponDTOList.addAll(storeCoupons); } List ids = memberCouponDTOList.stream().map(e -> e.getMemberCoupon().getId()).collect(Collectors.toList()); memberCouponService.used(tradeDTO.getMemberId(), ids); memberCouponDTOList.forEach(e -> couponService.usedCoupon(e.getMemberCoupon().getCouponId(), 1)); } /** * 创建交易,积分处理 * * @param tradeDTO 购物车视图 */ private void pointPretreatment(TradeDTO tradeDTO) { //需要支付积分 if (tradeDTO.getPriceDetailDTO() != null && tradeDTO.getPriceDetailDTO().getPayPoint() != null && tradeDTO.getPriceDetailDTO().getPayPoint() > 0) { StringBuilder orderSns = new StringBuilder(); for (CartVO item : tradeDTO.getCartList()) { orderSns.append(item.getSn()); } boolean result = memberService.updateMemberPoint(tradeDTO.getPriceDetailDTO().getPayPoint(), PointTypeEnum.REDUCE.name(), tradeDTO.getMemberId(), "订单【" + orderSns + "】创建,积分扣减"); if (!result) { throw new ServiceException(ResultCode.PAY_POINT_ENOUGH); } } } /** * 创建交易、砍价处理 * * @param tradeDTO 购物车视图 */ private void kanjiaPretreatment(TradeDTO tradeDTO) { if (tradeDTO.getCartTypeEnum().equals(CartTypeEnum.KANJIA)) { String kanjiaId = tradeDTO.getSkuList().get(0).getKanjiaId(); kanjiaActivityService.endKanjiaActivity(kanjiaId); } } } \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/statistics/entity/vo/StoreIndexStatisticsVO.java b/framework/src/main/java/cn/lili/modules/statistics/entity/vo/StoreIndexStatisticsVO.java index d3d2d5d5..9d2da2ae 100644 --- a/framework/src/main/java/cn/lili/modules/statistics/entity/vo/StoreIndexStatisticsVO.java +++ b/framework/src/main/java/cn/lili/modules/statistics/entity/vo/StoreIndexStatisticsVO.java @@ -47,5 +47,8 @@ public class StoreIndexStatisticsVO { @ApiModelProperty(value = "未对账结算单数量") private Long waitPayBill; + @ApiModelProperty(value = "待自提数量") + private Long selfPickNum; + } diff --git a/framework/src/main/java/cn/lili/modules/statistics/serviceimpl/IndexStatisticsServiceImpl.java b/framework/src/main/java/cn/lili/modules/statistics/serviceimpl/IndexStatisticsServiceImpl.java index fa5a7fae..0ce96a9b 100644 --- a/framework/src/main/java/cn/lili/modules/statistics/serviceimpl/IndexStatisticsServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/statistics/serviceimpl/IndexStatisticsServiceImpl.java @@ -200,7 +200,8 @@ public class IndexStatisticsServiceImpl implements IndexStatisticsService { storeIndexStatisticsVO.setUnDeliveredOrder(orderStatisticsService.orderNum(OrderStatusEnum.UNDELIVERED.name())); //待收货订单数量 storeIndexStatisticsVO.setDeliveredOrder(orderStatisticsService.orderNum(OrderStatusEnum.DELIVERED.name())); - + //待自提数量 + storeIndexStatisticsVO.setSelfPickNum(orderStatisticsService.orderNum(OrderStatusEnum.STAY_PICKED_UP.name())); //待处理退货数量 storeIndexStatisticsVO.setReturnGoods(afterSaleStatisticsService.applyNum(AfterSaleTypeEnum.RETURN_GOODS.name())); //待处理退款数量 diff --git a/framework/src/main/java/cn/lili/modules/store/entity/dos/Store.java b/framework/src/main/java/cn/lili/modules/store/entity/dos/Store.java index 8958a59d..0c478eca 100644 --- a/framework/src/main/java/cn/lili/modules/store/entity/dos/Store.java +++ b/framework/src/main/java/cn/lili/modules/store/entity/dos/Store.java @@ -103,6 +103,9 @@ public class Store extends BaseEntity { @ApiModelProperty(value = "默认页面是否开启") private Boolean pageShow; + @ApiModelProperty(value = "是否开启自提") + private Boolean selfPickFlag; + public Store(Member member) { this.memberId = member.getId(); this.memberName = member.getUsername(); diff --git a/framework/src/main/java/cn/lili/modules/store/entity/dto/StoreSettingDTO.java b/framework/src/main/java/cn/lili/modules/store/entity/dto/StoreSettingDTO.java index 18fb43ae..dff11df5 100644 --- a/framework/src/main/java/cn/lili/modules/store/entity/dto/StoreSettingDTO.java +++ b/framework/src/main/java/cn/lili/modules/store/entity/dto/StoreSettingDTO.java @@ -36,4 +36,7 @@ public class StoreSettingDTO { @ApiModelProperty(value = "默认页面是否开启") private Boolean pageShow; + @ApiModelProperty(value = "是否开启自提") + private Boolean selfPickFlag; + } diff --git a/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java b/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java index d08fdb51..3bbdd2c0 100644 --- a/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java +++ b/seller-api/src/main/java/cn/lili/controller/order/OrderStoreController.java @@ -149,6 +149,16 @@ public class OrderStoreController { return ResultUtil.data(orderService.take(orderSn, verificationCode)); } + @PreventDuplicateSubmissions + @ApiOperation(value = "订单核验") + @ApiImplicitParams({ + @ApiImplicitParam(name = "verificationCode", value = "核验码", required = true, paramType = "path") + }) + @PutMapping(value = "/take/{verificationCode}") + public ResultMessage take(@PathVariable String verificationCode) { + return ResultUtil.data(orderService.take(verificationCode)); + } + @ApiOperation(value = "查询物流踪迹") @ApiImplicitParam(name = "orderSn", value = "订单编号", required = true, dataType = "String", paramType = "path") @GetMapping(value = "/getTraces/{orderSn}") From 340b5b72485900fac1e140b1d5db04e1f22320d9 Mon Sep 17 00:00:00 2001 From: chc <1501738723@qq.com> Date: Tue, 22 Nov 2022 17:31:45 +0800 Subject: [PATCH 02/18] im --- .../im/config/CustomSpringConfigurator.java | 34 ++++ .../lili/im/config/WebSocketConfigurator.java | 24 +++ .../java/cn/lili/im/entity/ImMessage.java | 49 +++++ .../main/java/cn/lili/im/entity/ImTalk.java | 97 ++++++++++ .../main/java/cn/lili/im/entity/ImUser.java | 26 +++ .../im/entity/dto/MessageQueryParams.java | 49 +++++ .../im/entity/enums/MessageResultType.java | 28 +++ .../cn/lili/im/entity/enums/MessageType.java | 21 +++ .../lili/im/entity/enums/OperationType.java | 26 +++ .../java/cn/lili/im/entity/vo/ImTalkVO.java | 78 ++++++++ .../lili/im/entity/vo/MessageOperation.java | 48 +++++ .../java/cn/lili/im/entity/vo/MessageVO.java | 26 +++ .../cn/lili/im/entity/vo/ReadMessage.java | 17 ++ .../cn/lili/im/mapper/ImMessageMapper.java | 12 ++ .../java/cn/lili/im/mapper/ImTalkMapper.java | 12 ++ .../java/cn/lili/im/mapper/ImUserMapper.java | 13 ++ .../cn/lili/im/service/ImMessageService.java | 44 +++++ .../cn/lili/im/service/ImTalkService.java | 36 ++++ .../cn/lili/im/service/ImUserService.java | 21 +++ .../im/serviceimpl/ImMessageServiceImpl.java | 69 +++++++ .../im/serviceimpl/ImTalkServiceImpl.java | 92 +++++++++ .../im/serviceimpl/ImUserServiceImpl.java | 39 ++++ .../permission/service/AdminUserService.java | 8 + .../serviceimpl/AdminUserServiceImpl.java | 15 ++ .../cn/lili/mybatis/BaseTenantEntity.java | 24 +++ .../controller/im/ImManagerController.java | 175 ++++++++++++++++++ 26 files changed, 1083 insertions(+) create mode 100644 framework/src/main/java/cn/lili/im/config/CustomSpringConfigurator.java create mode 100644 framework/src/main/java/cn/lili/im/config/WebSocketConfigurator.java create mode 100644 framework/src/main/java/cn/lili/im/entity/ImMessage.java create mode 100644 framework/src/main/java/cn/lili/im/entity/ImTalk.java create mode 100644 framework/src/main/java/cn/lili/im/entity/ImUser.java create mode 100644 framework/src/main/java/cn/lili/im/entity/dto/MessageQueryParams.java create mode 100644 framework/src/main/java/cn/lili/im/entity/enums/MessageResultType.java create mode 100644 framework/src/main/java/cn/lili/im/entity/enums/MessageType.java create mode 100644 framework/src/main/java/cn/lili/im/entity/enums/OperationType.java create mode 100644 framework/src/main/java/cn/lili/im/entity/vo/ImTalkVO.java create mode 100644 framework/src/main/java/cn/lili/im/entity/vo/MessageOperation.java create mode 100644 framework/src/main/java/cn/lili/im/entity/vo/MessageVO.java create mode 100644 framework/src/main/java/cn/lili/im/entity/vo/ReadMessage.java create mode 100644 framework/src/main/java/cn/lili/im/mapper/ImMessageMapper.java create mode 100644 framework/src/main/java/cn/lili/im/mapper/ImTalkMapper.java create mode 100644 framework/src/main/java/cn/lili/im/mapper/ImUserMapper.java create mode 100644 framework/src/main/java/cn/lili/im/service/ImMessageService.java create mode 100644 framework/src/main/java/cn/lili/im/service/ImTalkService.java create mode 100644 framework/src/main/java/cn/lili/im/service/ImUserService.java create mode 100644 framework/src/main/java/cn/lili/im/serviceimpl/ImMessageServiceImpl.java create mode 100644 framework/src/main/java/cn/lili/im/serviceimpl/ImTalkServiceImpl.java create mode 100644 framework/src/main/java/cn/lili/im/serviceimpl/ImUserServiceImpl.java create mode 100644 framework/src/main/java/cn/lili/mybatis/BaseTenantEntity.java create mode 100644 manager-api/src/main/java/cn/lili/controller/im/ImManagerController.java diff --git a/framework/src/main/java/cn/lili/im/config/CustomSpringConfigurator.java b/framework/src/main/java/cn/lili/im/config/CustomSpringConfigurator.java new file mode 100644 index 00000000..a09cc961 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/config/CustomSpringConfigurator.java @@ -0,0 +1,34 @@ +package cn.lili.im.config; + + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import javax.websocket.server.ServerEndpointConfig; + +/** + * CustomSpringConfigurator + * + * @author Chopper + * @version v1.0 + * 2021-12-31 11:53 + */ +public class CustomSpringConfigurator extends ServerEndpointConfig.Configurator implements ApplicationContextAware { + + /** + * Spring application context. + */ + private static volatile BeanFactory context; + + @Override + public T getEndpointInstance(Class clazz) throws InstantiationException { + return context.getBean(clazz); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + CustomSpringConfigurator.context = applicationContext; + } +} diff --git a/framework/src/main/java/cn/lili/im/config/WebSocketConfigurator.java b/framework/src/main/java/cn/lili/im/config/WebSocketConfigurator.java new file mode 100644 index 00000000..af42081e --- /dev/null +++ b/framework/src/main/java/cn/lili/im/config/WebSocketConfigurator.java @@ -0,0 +1,24 @@ +package cn.lili.im.config; + + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * WebSocketConfigurator + * + * @author Chopper + * @version v1.0 + * 2021-12-31 11:53 + */ +@ConditionalOnWebApplication +@Configuration +public class WebSocketConfigurator { + + @Bean + public CustomSpringConfigurator customSpringConfigurator() { + // This is just to get context + return new CustomSpringConfigurator(); + } +} diff --git a/framework/src/main/java/cn/lili/im/entity/ImMessage.java b/framework/src/main/java/cn/lili/im/entity/ImMessage.java new file mode 100644 index 00000000..ccc58d49 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/ImMessage.java @@ -0,0 +1,49 @@ +package cn.lili.im.entity; + +import cn.lili.im.entity.enums.MessageType; +import cn.lili.mybatis.BaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +/** + * @author Chopper + */ +@Data +@TableName("li_im_message") +@ApiModel(value = "Im消息") +public class ImMessage extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 发送者 + */ + private String fromUser; + + /** + * 接收者 + */ + private String toUser; + + /** + * 已阅 + */ + private Boolean isRead; + + /** + * 消息类型 + */ + private MessageType messageType; + + /** + * 聊天id + */ + private String talkId; + + /** + * 消息实体 + */ + private String text; + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/entity/ImTalk.java b/framework/src/main/java/cn/lili/im/entity/ImTalk.java new file mode 100644 index 00000000..9eb8502c --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/ImTalk.java @@ -0,0 +1,97 @@ +package cn.lili.im.entity; + + +import cn.lili.common.utils.SnowFlake; +import cn.lili.mybatis.BaseTenantEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @author Chopper + */ +@Data +@TableName("li_im_talk") +@ApiModel(value = "聊天") +public class ImTalk extends BaseTenantEntity { + + private static final long serialVersionUID = 1L; + + /** + * 用户1 id小的排在1 + */ + private String userId1; + /** + * 用户1 id大的排在2 + */ + private String userId2; + + /** + * 用户1置顶 + */ + private Boolean top1; + + /** + * 用户2置顶 + */ + private Boolean top2; + /** + * 用户1 不可见 + */ + private Boolean disable1; + + /** + * 用户2 不可见 + */ + private Boolean disable2; + /** + * 用户1名字 + */ + private String name1; + + /** + * 用户2名字 + */ + private String name2; + /** + * 用户1头像 + */ + private String face1; + + /** + * 用户2头像 + */ + private String face2; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty(value = "最后聊天时间", hidden = true) + private Date lastTalkTime; + + public ImTalk() { + + } + + public ImTalk(String userId1, String userId2, + String face1, String face2, + String name1, String name2 + ) { + this.userId1 = userId1; + this.userId2 = userId2; + this.top1 = false; + this.top2 = false; + this.disable1 = false; + this.disable2 = false; + this.setId(SnowFlake.getIdStr()); + this.lastTalkTime = new Date(); + this.face1 = face1; + this.face2 = face2; + this.name1 = name1; + this.name2 = name2; + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/entity/ImUser.java b/framework/src/main/java/cn/lili/im/entity/ImUser.java new file mode 100644 index 00000000..0be58571 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/ImUser.java @@ -0,0 +1,26 @@ +package cn.lili.im.entity; + + +import cn.lili.mybatis.BaseTenantEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +/** + * @author Chopper + */ +@Data +@TableName("li_im_users") +@ApiModel(value = "Im消息") +public class ImUser extends BaseTenantEntity { + + private static final long serialVersionUID = 1L; + /** + * 头像 + */ + private String face; + /** + * 昵称 + */ + private String name; +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/entity/dto/MessageQueryParams.java b/framework/src/main/java/cn/lili/im/entity/dto/MessageQueryParams.java new file mode 100644 index 00000000..f10da119 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/dto/MessageQueryParams.java @@ -0,0 +1,49 @@ +package cn.lili.im.entity.dto; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.utils.StringUtils; +import cn.lili.im.entity.ImMessage; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.Data; + +/** + * MessageQueryParams + * + * @author Chopper + * @version v1.0 + * 2022-01-20 17:16 + */ +@Data +public class MessageQueryParams { + /** + * 聊天窗口 + */ + private String talkId; + /** + * 最后一个消息 + */ + private String lastMessageId; + /** + * 获取消息数量 + */ + private Integer num; + + public LambdaQueryWrapper initQueryWrapper() { + if (StringUtils.isEmpty(talkId)) { + throw new ServiceException(ResultCode.ERROR); + } + if (num == null || num > 50) { + num = 50; + } + + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(ImMessage::getTalkId, talkId); + if (StringUtils.isNotEmpty(lastMessageId)) { + lambdaQueryWrapper.lt(ImMessage::getId, lastMessageId); + } + lambdaQueryWrapper.orderByDesc(ImMessage::getId); + lambdaQueryWrapper.last("limit " + num); + return lambdaQueryWrapper; + } +} diff --git a/framework/src/main/java/cn/lili/im/entity/enums/MessageResultType.java b/framework/src/main/java/cn/lili/im/entity/enums/MessageResultType.java new file mode 100644 index 00000000..ed268da8 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/enums/MessageResultType.java @@ -0,0 +1,28 @@ +package cn.lili.im.entity.enums; + +/** + * 返回消息类型枚举 + * + * @author liushuai + */ +public enum MessageResultType { + /** + * 返回消息类型枚举 + *

+ * 好友列表 + * 增加好友 + * 消息 + * 阅读消息 + * 未读消息 + * 历史消息 + * 系统提示 + */ + FRIENDS, + ADD_FRIENDS, + MESSAGE, + READ_MESSAGE, + UN_READ, + HISTORY, + SYSTEM_TIPS + +} diff --git a/framework/src/main/java/cn/lili/im/entity/enums/MessageType.java b/framework/src/main/java/cn/lili/im/entity/enums/MessageType.java new file mode 100644 index 00000000..593afd78 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/enums/MessageType.java @@ -0,0 +1,21 @@ +package cn.lili.im.entity.enums; + +/** + * 消息类型 + * + * @author liushuai + */ +public enum MessageType { + /** + * 消息类型枚举 + *

+ * 普通消息 + * 图片 + * 语音 + * 视频 + */ + MESSAGE, + PICTURE, + VOICE, + VIDEO +} diff --git a/framework/src/main/java/cn/lili/im/entity/enums/OperationType.java b/framework/src/main/java/cn/lili/im/entity/enums/OperationType.java new file mode 100644 index 00000000..4c68971a --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/enums/OperationType.java @@ -0,0 +1,26 @@ +package cn.lili.im.entity.enums; + +/** + * 操作类型枚举 + * + * @author liushuai + */ +public enum OperationType { + /** + * 消息类型枚举 + *

+ * 心跳检测 + * 发起聊天 + * 发起消息 + * 查询历史消息 + * 阅读消息 + * 查询未读消息 + */ + PING, + CREATE, + MESSAGE, + HISTORY, + READ, + UNREAD, + +} diff --git a/framework/src/main/java/cn/lili/im/entity/vo/ImTalkVO.java b/framework/src/main/java/cn/lili/im/entity/vo/ImTalkVO.java new file mode 100644 index 00000000..b3707452 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/vo/ImTalkVO.java @@ -0,0 +1,78 @@ +package cn.lili.im.entity.vo; + +import cn.lili.im.entity.ImTalk; +import cn.lili.mybatis.BaseTenantEntity; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @author Chopper + */ +@Data +@ApiModel(value = "聊天") +public class ImTalkVO extends BaseTenantEntity { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + private String id; + /** + * 用户 id + */ + private String userId; + + /** + * 置顶 + */ + private Boolean top; + + /** + * 用户 不可见 + */ + private Boolean disable; + + /** + * 用户名字 + */ + private String name; + + /** + * 用户头像 + */ + private String face; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty(value = "最后聊天时间", hidden = true) + private Date lastTalkTime; + + public ImTalkVO() { + + } + + public ImTalkVO(ImTalk imTalk, String currentUser) { + if (imTalk.getUserId2().equals(currentUser)) { + userId = imTalk.getUserId1(); + top = imTalk.getTop1(); + disable = imTalk.getDisable1(); + name = imTalk.getName1(); + face = imTalk.getFace1(); + } else { + userId = imTalk.getUserId2(); + top = imTalk.getTop2(); + disable = imTalk.getDisable2(); + name = imTalk.getName2(); + face = imTalk.getFace2(); + } + + lastTalkTime = imTalk.getLastTalkTime(); + id = imTalk.getId(); + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/entity/vo/MessageOperation.java b/framework/src/main/java/cn/lili/im/entity/vo/MessageOperation.java new file mode 100644 index 00000000..602e3b9b --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/vo/MessageOperation.java @@ -0,0 +1,48 @@ +package cn.lili.im.entity.vo; + +import cn.lili.common.utils.StringUtils; +import cn.lili.im.entity.enums.MessageType; +import cn.lili.im.entity.enums.OperationType; +import lombok.Data; + +/** + * @author liushuai + */ +@Data +public class MessageOperation { + + /** + * 消息类型 + */ + private OperationType operationType; + /** + * 与某人聊天记录 + */ + private String to; + + /** + * 聊天id + */ + private String talkId; + + /** + * 消息类型 + */ + private MessageType messageType; + /** + * 消息内容 + */ + private String context; + + public void setOperationType(String operationType) { + if (!StringUtils.isEmpty(operationType)) { + this.operationType = OperationType.valueOf(operationType); + } + } + + public void setMessageType(String messageType) { + if (!StringUtils.isEmpty(messageType)) { + this.messageType = MessageType.valueOf(messageType); + } + } +} diff --git a/framework/src/main/java/cn/lili/im/entity/vo/MessageVO.java b/framework/src/main/java/cn/lili/im/entity/vo/MessageVO.java new file mode 100644 index 00000000..5c4b0222 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/vo/MessageVO.java @@ -0,0 +1,26 @@ +package cn.lili.im.entity.vo; + +import cn.lili.im.entity.enums.MessageResultType; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * MessageVO + * + * @author Chopper + * @version v1.0 + * 2021-12-30 15:51 + */ +@Data +@AllArgsConstructor +public class MessageVO { + + /** + * 消息类型 + */ + private MessageResultType messageResultType; + /** + * 消息内容 + */ + private Object result; +} diff --git a/framework/src/main/java/cn/lili/im/entity/vo/ReadMessage.java b/framework/src/main/java/cn/lili/im/entity/vo/ReadMessage.java new file mode 100644 index 00000000..64b20f86 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/entity/vo/ReadMessage.java @@ -0,0 +1,17 @@ +package cn.lili.im.entity.vo; + +import lombok.Data; + +import java.util.List; + +/** + * ReadMessage + * + * @author Chopper + * @version v1.0 + * 2021-12-31 11:13 + */ +@Data +public class ReadMessage { + private List readMessageList; +} diff --git a/framework/src/main/java/cn/lili/im/mapper/ImMessageMapper.java b/framework/src/main/java/cn/lili/im/mapper/ImMessageMapper.java new file mode 100644 index 00000000..4b3ac1a1 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/mapper/ImMessageMapper.java @@ -0,0 +1,12 @@ +package cn.lili.im.mapper; + +import cn.lili.im.entity.ImMessage; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * Im消息 Dao层 + * @author Chopper + */ +public interface ImMessageMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/mapper/ImTalkMapper.java b/framework/src/main/java/cn/lili/im/mapper/ImTalkMapper.java new file mode 100644 index 00000000..4377dc59 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/mapper/ImTalkMapper.java @@ -0,0 +1,12 @@ +package cn.lili.im.mapper; + +import cn.lili.im.entity.ImTalk; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 聊天 Dao层 + * @author Chopper + */ +public interface ImTalkMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/mapper/ImUserMapper.java b/framework/src/main/java/cn/lili/im/mapper/ImUserMapper.java new file mode 100644 index 00000000..8cb2340b --- /dev/null +++ b/framework/src/main/java/cn/lili/im/mapper/ImUserMapper.java @@ -0,0 +1,13 @@ +package cn.lili.im.mapper; + +import cn.lili.im.entity.ImUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * Im消息 Dao层 + * + * @author Chopper + */ +public interface ImUserMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/service/ImMessageService.java b/framework/src/main/java/cn/lili/im/service/ImMessageService.java new file mode 100644 index 00000000..7b58c900 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/service/ImMessageService.java @@ -0,0 +1,44 @@ +package cn.lili.im.service; + +import cn.lili.im.entity.ImMessage; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + * Im消息 业务层 + * + * @author Chopper + */ +public interface ImMessageService extends IService { + + /** + * 阅读消息 + * + * @param talkId + * @param accessToken + */ + void read(String talkId, String accessToken); + + /** + * 未读消息列表 + * + * @param accessToken + */ + List unReadMessages(String accessToken); + + /** + * 历史消息 + * + * @param accessToken + * @param to + */ + List historyMessage(String accessToken, String to); + + /** + * 是否有新消息 + * @param accessToken + * @return + */ + Boolean hasNewMessage(String accessToken); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/service/ImTalkService.java b/framework/src/main/java/cn/lili/im/service/ImTalkService.java new file mode 100644 index 00000000..f9919cd6 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/service/ImTalkService.java @@ -0,0 +1,36 @@ +package cn.lili.im.service; + +import cn.lili.im.entity.ImTalk; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 聊天 业务层 + * + * @author Chopper + */ +public interface ImTalkService extends IService { + + /** + * 获取与某人的聊天框 + * + * @param userId1 + * @param userId2 + * @return + */ + ImTalk getTalkByUser(String userId1, String userId2); + + /** + * 置顶消息 + * + * @param id + * @param top + */ + void top(String id, Boolean top); + + /** + * 禁用(前端不做展示)聊天 + * + * @param id + */ + void disable(String id); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/service/ImUserService.java b/framework/src/main/java/cn/lili/im/service/ImUserService.java new file mode 100644 index 00000000..e825f87b --- /dev/null +++ b/framework/src/main/java/cn/lili/im/service/ImUserService.java @@ -0,0 +1,21 @@ +package cn.lili.im.service; + +import cn.lili.im.entity.ImUser; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * Im消息 业务层 + * + * @author Chopper + */ +public interface ImUserService extends IService { + + /** + * 注册用户 + * + * @param accessToken + * @return + */ + ImUser register(String accessToken); + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/serviceimpl/ImMessageServiceImpl.java b/framework/src/main/java/cn/lili/im/serviceimpl/ImMessageServiceImpl.java new file mode 100644 index 00000000..6f2fa9a3 --- /dev/null +++ b/framework/src/main/java/cn/lili/im/serviceimpl/ImMessageServiceImpl.java @@ -0,0 +1,69 @@ +package cn.lili.im.serviceimpl; + +import cn.lili.common.security.context.UserContext; +import cn.lili.im.entity.ImMessage; +import cn.lili.im.mapper.ImMessageMapper; +import cn.lili.im.service.ImMessageService; +import cn.lili.im.service.ImTalkService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * Im消息 业务实现 + * + * @author Chopper + */ +@Service +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ImMessageServiceImpl extends ServiceImpl implements ImMessageService { + + @Autowired + private ImTalkService imTalkService; + + @Override + public void read(String talkId, String accessToken) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + String userId = UserContext.getAuthUser(accessToken).getId(); + updateWrapper.eq(ImMessage::getTalkId, talkId); + updateWrapper.eq(ImMessage::getToUser, userId); + updateWrapper.set(ImMessage::getIsRead, true); + this.update(updateWrapper); + } + + @Override + public List unReadMessages(String accessToken) { + String userId = UserContext.getAuthUser(accessToken).getId(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ImMessage::getToUser, userId); + queryWrapper.eq(ImMessage::getIsRead, false); + return this.list(queryWrapper); + } + + @Override + public List historyMessage(String accessToken, String to) { + String userId = UserContext.getAuthUser(accessToken).getId(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.and(i -> i.eq(ImMessage::getToUser, userId).and(j -> j.eq(ImMessage::getFromUser, to))); + queryWrapper.or(i -> i.eq(ImMessage::getToUser, to).and(j -> j.eq(ImMessage::getFromUser, userId))); + queryWrapper.orderByDesc(ImMessage::getCreateTime); + return this.list(queryWrapper); + } + + @Override + public Boolean hasNewMessage(String accessToken) { + String userId = UserContext.getAuthUser(accessToken).getId(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ImMessage::getIsRead, false); + queryWrapper.eq(ImMessage::getToUser, userId); + return this.list(queryWrapper).size() > 0; + + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/serviceimpl/ImTalkServiceImpl.java b/framework/src/main/java/cn/lili/im/serviceimpl/ImTalkServiceImpl.java new file mode 100644 index 00000000..a2f4c28a --- /dev/null +++ b/framework/src/main/java/cn/lili/im/serviceimpl/ImTalkServiceImpl.java @@ -0,0 +1,92 @@ +package cn.lili.im.serviceimpl; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.context.UserContext; +import cn.lili.im.entity.ImTalk; +import cn.lili.im.entity.ImUser; +import cn.lili.im.mapper.ImTalkMapper; +import cn.lili.im.service.ImTalkService; +import cn.lili.im.service.ImUserService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 聊天 业务实现 + * + * @author Chopper + */ +@Service +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ImTalkServiceImpl extends ServiceImpl implements ImTalkService { + + @Autowired + private ImUserService imUserService; + + @Override + public ImTalk getTalkByUser(String userId1, String userId2) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ImTalk::getUserId2, userId2); + queryWrapper.eq(ImTalk::getUserId1, userId1); + ImTalk imTalk = this.getOne(queryWrapper); + ImUser imUser1 = imUserService.getById(userId1); + ImUser imUser2 = imUserService.getById(userId2); + + //如果没有聊天,则创建聊天 + if (imTalk == null) { + if (imUser1 == null || imUser2 == null) { + return null; + } + imTalk = new ImTalk(userId1, userId2, imUser1.getFace(), imUser2.getFace(), imUser1.getName(), imUser2.getName()); + this.save(imTalk); + } else { + imTalk = check(imTalk); + } + return imTalk; + } + + /** + * 发起聊天后,如果聊天不可见为true,则需要修正 + * + * @param imTalk + */ + private ImTalk check(ImTalk imTalk) { + if (imTalk.getDisable1() || imTalk.getDisable2()) { + imTalk.setDisable1(false); + imTalk.setDisable2(false); + this.updateById(imTalk); + + } + return imTalk; + } + + @Override + public void top(String id, Boolean top) { + ImTalk imTalk = this.getById(id); + if (imTalk.getUserId1().equals(UserContext.getCurrentUser().getId())) { + imTalk.setTop1(top); + } else if (imTalk.getUserId2().equals(UserContext.getCurrentUser().getId())) { + imTalk.setTop2(top); + } else { + throw new ServiceException(ResultCode.ERROR); + } + this.updateById(imTalk); + } + + @Override + public void disable(String id) { + ImTalk imTalk = this.getById(id); + if (imTalk.getUserId1().equals(UserContext.getCurrentUser().getId())) { + imTalk.setDisable1(true); + this.updateById(imTalk); + } else if (imTalk.getUserId2().equals(UserContext.getCurrentUser().getId())) { + imTalk.setDisable2(true); + this.updateById(imTalk); + } + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/im/serviceimpl/ImUserServiceImpl.java b/framework/src/main/java/cn/lili/im/serviceimpl/ImUserServiceImpl.java new file mode 100644 index 00000000..fe92173e --- /dev/null +++ b/framework/src/main/java/cn/lili/im/serviceimpl/ImUserServiceImpl.java @@ -0,0 +1,39 @@ +package cn.lili.im.serviceimpl; + +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.context.UserContext; +import cn.lili.im.entity.ImUser; +import cn.lili.im.mapper.ImUserMapper; +import cn.lili.im.service.ImUserService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * Im消息 业务实现 + * + * @author Chopper + */ +@Service +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ImUserServiceImpl extends ServiceImpl implements ImUserService { + + @Override + public ImUser register(String accessToken) { + AuthUser authUser = UserContext.getAuthUser(accessToken); + ImUser imUser; + //如果用户存在 + imUser = this.getById(authUser.getId()); + if (imUser == null) { + imUser = new ImUser(); + imUser.setId(authUser.getId()); + imUser.setName(authUser.getNickName()); + this.save(imUser); + } + return imUser; + } + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/permission/service/AdminUserService.java b/framework/src/main/java/cn/lili/modules/permission/service/AdminUserService.java index 7257ca22..edc55c6e 100644 --- a/framework/src/main/java/cn/lili/modules/permission/service/AdminUserService.java +++ b/framework/src/main/java/cn/lili/modules/permission/service/AdminUserService.java @@ -1,6 +1,7 @@ package cn.lili.modules.permission.service; +import cn.lili.common.security.enums.UserEnums; import cn.lili.common.security.token.Token; import cn.lili.modules.permission.entity.dos.AdminUser; import cn.lili.modules.permission.entity.dto.AdminUserDTO; @@ -99,4 +100,11 @@ public interface AdminUserService extends IService { */ Token refreshToken(String refreshToken); + /** + * 登出 + * + * @param userEnums token角色类型 + */ + void logout(UserEnums userEnums); + } diff --git a/framework/src/main/java/cn/lili/modules/permission/serviceimpl/AdminUserServiceImpl.java b/framework/src/main/java/cn/lili/modules/permission/serviceimpl/AdminUserServiceImpl.java index 53ec3049..bc4f55d4 100644 --- a/framework/src/main/java/cn/lili/modules/permission/serviceimpl/AdminUserServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/permission/serviceimpl/AdminUserServiceImpl.java @@ -1,10 +1,13 @@ package cn.lili.modules.permission.serviceimpl; import cn.hutool.core.text.CharSequenceUtil; +import cn.lili.cache.Cache; +import cn.lili.cache.CachePrefix; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.security.AuthUser; import cn.lili.common.security.context.UserContext; +import cn.lili.common.security.enums.UserEnums; import cn.lili.common.security.token.Token; import cn.lili.common.utils.BeanUtil; import cn.lili.common.utils.StringUtils; @@ -53,6 +56,10 @@ public class AdminUserServiceImpl extends ServiceImpl