diff --git a/DB/version4.2.4toMASTER.sql b/DB/version4.2.4toMASTER.sql deleted file mode 100644 index a00128f7..00000000 --- a/DB/version4.2.4toMASTER.sql +++ /dev/null @@ -1,51 +0,0 @@ -/** 增加签到日期 **/ -ALTER TABLE li_member_sign - ADD day int DEFAULT NULL COMMENT '签到日 '; -ALTER TABLE li_member_sign - DROP INDEX uk_member_day; -ALTER TABLE li_member_sign - add unique uk_member_day (member_id, day) COMMENT 'uk_member_day'; - - - --- ---------------------------- --- Table structure for li_hot_words_history --- ---------------------------- -DROP TABLE IF EXISTS `li_hot_words_history`; -CREATE TABLE `li_hot_words_history` -( - `id` bigint NOT NULL COMMENT 'ID', - `create_time` datetime(6) DEFAULT NULL COMMENT '创建时间', - `keywords` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '热词', - `score` int DEFAULT NULL COMMENT '热词分数', - PRIMARY KEY (`id`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb3 COLLATE = utf8_bin COMMENT '热词历史表'; - --- ---------------------------- --- Records of li_hot_words_history --- ---------------------------- - --- ---------------------------- --- Table structure for li_wholesale --- ---------------------------- -DROP TABLE IF EXISTS `li_wholesale`; -CREATE TABLE `li_wholesale` -( - `id` bigint NOT NULL, - `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, - `create_time` datetime(6) DEFAULT NULL, - `delete_flag` bit(1) DEFAULT NULL, - `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, - `update_time` datetime(6) DEFAULT NULL, - `price` decimal(10, 2) DEFAULT NULL COMMENT '价格', - `goods_id` bigint DEFAULT NULL COMMENT '商品id', - `sku_id` bigint DEFAULT NULL COMMENT '商品skuId', - `num` int DEFAULT NULL COMMENT '起购量', - PRIMARY KEY (`id`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_bin COMMENT '批发规则表'; - -ALTER TABLE li_wholesale - ADD template_id bigint DEFAULT NULL COMMENT '商品模版id'; - -/** 店铺--默认页面是否开启**/ -ALTER TABLE li_store ADD page_show bit(1) DEFAULT NULL COMMENT '默认页面是否开启'; \ No newline at end of file diff --git a/DB/version4.2.5toMASTER.sql b/DB/version4.2.5toMASTER.sql new file mode 100644 index 00000000..a57e2b6c --- /dev/null +++ b/DB/version4.2.5toMASTER.sql @@ -0,0 +1,79 @@ +-- 会员优惠券标识 +CREATE TABLE `li_member_coupon_sign` ( + `id` bigint NOT NULL, + `coupon_activity_Id` bigint NULL DEFAULT NULL COMMENT '优惠券活动id', + `member_id` bigint NULL DEFAULT NULL COMMENT '会员id', + `invalid_time` datetime NULL DEFAULT NULL COMMENT '过期时间', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = DYNAMIC; + +/** + IM聊天 + */ +CREATE TABLE `li_im_talk` ( + `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `delete_flag` bit(1) DEFAULT NULL COMMENT '删除标志', + `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改者', + `update_time` datetime(6) DEFAULT NULL COMMENT '修改时间', + `user_id1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户1Id', + `user_id2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户2Id', + `name1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户1名称', + `name2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户2名称', + `face1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户1头像', + `face2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户2头像', + `top1` bit(1) DEFAULT NULL COMMENT '用户1置顶标识', + `top2` bit(1) DEFAULT NULL COMMENT '用户2置顶标识', + `disable1` bit(1) DEFAULT NULL COMMENT '用户1禁用标识', + `disable2` bit(1) DEFAULT NULL COMMENT '用户2禁用标识', + `store_flag1` bit(1) DEFAULT NULL COMMENT '用户1店铺标识', + `store_flag2` bit(1) DEFAULT NULL COMMENT '用户2店铺标识', + `last_talk_time` datetime DEFAULT NULL COMMENT '最后聊天时间', + `last_talk_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '最后的消息', + `last_message_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '最后消息类型', + `talk_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '聊天Id', + `tenant_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '坐席Id', + `tenant_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '坐席名称', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +/** + IM消息 + */ +CREATE TABLE `li_im_message` ( + `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `delete_flag` bit(1) DEFAULT NULL COMMENT '删除标识', + `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '修改者', + `update_time` datetime(6) DEFAULT NULL COMMENT '修改标识', + `from_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '发送用户Id', + `to_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '接收用户Id', + `is_read` bit(1) DEFAULT NULL COMMENT '已读标识', + `message_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '聊天类型', + `text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '聊天内容', + `talk_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '聊天Id', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + + + +/** + 订单增加自提信息 + */ +ALTER TABLE li_order ADD `store_address_path` varchar(255) DEFAULT NULL; +ALTER TABLE li_order ADD `store_address_center` varchar(255) DEFAULT NULL; +ALTER TABLE li_order ADD `store_address_mobile` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL; + +/** + 店铺是否开启自提 + */ +ALTER TABLE li_store ADD `self_pick_flag` bit(1) DEFAULT NULL; +/** + 历史足迹增加店铺Id + */ +ALTER TABLE li_foot_print ADD `store_id` varchar(255) DEFAULT NULL COMMENT '店铺ID'; \ No newline at end of file diff --git a/buyer-api/src/main/java/cn/lili/controller/member/FootprintController.java b/buyer-api/src/main/java/cn/lili/controller/member/FootprintController.java index e5de7c6b..951e56ec 100644 --- a/buyer-api/src/main/java/cn/lili/controller/member/FootprintController.java +++ b/buyer-api/src/main/java/cn/lili/controller/member/FootprintController.java @@ -1,14 +1,17 @@ package cn.lili.controller.member; import cn.lili.common.enums.ResultUtil; +import cn.lili.common.security.context.UserContext; import cn.lili.common.vo.PageVO; import cn.lili.common.vo.ResultMessage; +import cn.lili.modules.member.entity.dto.FootPrintQueryParams; import cn.lili.modules.member.service.FootprintService; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import com.baomidou.mybatisplus.core.metadata.IPage; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; +import org.apache.catalina.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -35,8 +38,9 @@ public class FootprintController { @ApiOperation(value = "分页获取") @GetMapping - public ResultMessage> getByPage(PageVO page) { - return ResultUtil.data(footprintService.footPrintPage(page)); + public ResultMessage> getByPage(FootPrintQueryParams params) { + params.setMemberId(UserContext.getCurrentUser().getId()); + return ResultUtil.data(footprintService.footPrintPage(params)); } @ApiOperation(value = "根据id删除") 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/promotion/CouponBuyerController.java b/buyer-api/src/main/java/cn/lili/controller/promotion/CouponBuyerController.java index 4d0dfed4..e505cb58 100644 --- a/buyer-api/src/main/java/cn/lili/controller/promotion/CouponBuyerController.java +++ b/buyer-api/src/main/java/cn/lili/controller/promotion/CouponBuyerController.java @@ -7,11 +7,14 @@ import cn.lili.common.security.context.UserContext; import cn.lili.common.vo.PageVO; import cn.lili.common.vo.ResultMessage; import cn.lili.modules.promotion.entity.dos.MemberCoupon; +import cn.lili.modules.promotion.entity.dto.CouponActivityTrigger; import cn.lili.modules.promotion.entity.dto.search.CouponSearchParams; import cn.lili.modules.promotion.entity.dto.search.MemberCouponSearchParams; +import cn.lili.modules.promotion.entity.enums.CouponActivityTypeEnum; import cn.lili.modules.promotion.entity.enums.CouponGetEnum; import cn.lili.modules.promotion.entity.enums.PromotionsStatusEnum; import cn.lili.modules.promotion.entity.vos.CouponVO; +import cn.lili.modules.promotion.service.CouponActivityService; import cn.lili.modules.promotion.service.CouponService; import cn.lili.modules.promotion.service.MemberCouponService; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -26,6 +29,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.constraints.NotNull; +import java.util.List; import java.util.Objects; /** @@ -45,12 +49,30 @@ public class CouponBuyerController { @Autowired private CouponService couponService; + /** + * 优惠券活动 + */ + @Autowired + private CouponActivityService couponActivityService; + /** * 会员优惠券 */ @Autowired private MemberCouponService memberCouponService; + @GetMapping("/activity") + @ApiOperation(value = "自动领取优惠券") + public ResultMessage> activity() { + return ResultUtil.data(couponActivityService.trigger( + CouponActivityTrigger.builder() + .couponActivityTypeEnum(CouponActivityTypeEnum.AUTO_COUPON) + .nickName(UserContext.getCurrentUser().getNickName()) + .userId(UserContext.getCurrentUser().getId()) + .build()) + ); + } + @GetMapping @ApiOperation(value = "获取可领取优惠券列表") public ResultMessage> getCouponList(CouponSearchParams queryParam, PageVO page) { 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/buyer-api/src/main/resources/application.yml b/buyer-api/src/main/resources/application.yml index f3a7a5a6..04c87cf4 100644 --- a/buyer-api/src/main/resources/application.yml +++ b/buyer-api/src/main/resources/application.yml @@ -265,6 +265,8 @@ lili: order-group: lili_order_group member-topic: lili_member_topic member-group: lili_member_group + store-topic: lili_store_topic + store-group: lili_store_group other-topic: lili_other_topic other-group: lili_other_group notice-topic: lili_notice_topic diff --git a/consumer/src/main/java/cn/lili/event/MemberInfoChangeEvent.java b/consumer/src/main/java/cn/lili/event/MemberInfoChangeEvent.java new file mode 100644 index 00000000..51dbd391 --- /dev/null +++ b/consumer/src/main/java/cn/lili/event/MemberInfoChangeEvent.java @@ -0,0 +1,17 @@ +package cn.lili.event; + +import cn.lili.modules.member.entity.dos.Member; + +/** + * @author chc + * @since 2022/6/2114:46 + */ +public interface MemberInfoChangeEvent { + + /** + * 会员信息更改消息 + * + * @param member 会员信息 + */ + void memberInfoChange(Member member); +} diff --git a/consumer/src/main/java/cn/lili/event/StoreSettingChangeEvent.java b/consumer/src/main/java/cn/lili/event/StoreSettingChangeEvent.java new file mode 100644 index 00000000..53fb83b6 --- /dev/null +++ b/consumer/src/main/java/cn/lili/event/StoreSettingChangeEvent.java @@ -0,0 +1,18 @@ +package cn.lili.event; + + +import cn.lili.modules.store.entity.dos.Store; + +/** + * @author chc + * @since 2022/6/2114:46 + */ +public interface StoreSettingChangeEvent { + + /** + * 店铺信息更改消息 + * + * @param store 店铺信息 + */ + void storeSettingChange(Store store); +} 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/ImTalkExecute.java b/consumer/src/main/java/cn/lili/event/impl/ImTalkExecute.java new file mode 100644 index 00000000..b631589f --- /dev/null +++ b/consumer/src/main/java/cn/lili/event/impl/ImTalkExecute.java @@ -0,0 +1,60 @@ +package cn.lili.event.impl; + +import cn.lili.event.MemberInfoChangeEvent; +import cn.lili.event.StoreSettingChangeEvent; +import cn.lili.modules.im.entity.dos.ImTalk; +import cn.lili.modules.im.service.ImTalkService; +import cn.lili.modules.member.entity.dos.Member; +import cn.lili.modules.store.entity.dos.Store; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * Im对话消息 + * + * @author chc + * @since 2022/6/2114:46 + */ +@Service +public class ImTalkExecute implements MemberInfoChangeEvent, StoreSettingChangeEvent { + + @Autowired + private ImTalkService imTalkService; + + @Override + public void memberInfoChange(Member member) { + //当与UserId1相等时 + List imTalkList1 = imTalkService.list(new LambdaQueryWrapper().eq(ImTalk::getUserId1, member.getId())); + for (ImTalk imTalk : imTalkList1) { + imTalk.setName1(member.getNickName()); + imTalk.setFace1(member.getFace()); + } + imTalkService.updateBatchById(imTalkList1); + List imTalkList2 = imTalkService.list(new LambdaQueryWrapper().eq(ImTalk::getUserId2, member.getId())); + for (ImTalk imTalk : imTalkList2) { + imTalk.setName2(member.getNickName()); + imTalk.setFace2(member.getFace()); + } + imTalkService.updateBatchById(imTalkList2); + } + + @Override + public void storeSettingChange(Store store) { + //当与UserId1相等时 + List imTalkList1 = imTalkService.list(new LambdaQueryWrapper().eq(ImTalk::getUserId1, store.getId())); + for (ImTalk imTalk : imTalkList1) { + imTalk.setName1(store.getStoreName()); + imTalk.setFace1(store.getStoreLogo()); + } + imTalkService.updateBatchById(imTalkList1); + List imTalkList2 = imTalkService.list(new LambdaQueryWrapper().eq(ImTalk::getUserId2, store.getId())); + for (ImTalk imTalk : imTalkList2) { + imTalk.setName2(store.getStoreName()); + imTalk.setFace2(store.getStoreLogo()); + } + imTalkService.updateBatchById(imTalkList2); + } +} diff --git a/consumer/src/main/java/cn/lili/event/impl/RegisteredCouponActivityExecute.java b/consumer/src/main/java/cn/lili/event/impl/RegisteredCouponActivityExecute.java index a103b767..96892d48 100644 --- a/consumer/src/main/java/cn/lili/event/impl/RegisteredCouponActivityExecute.java +++ b/consumer/src/main/java/cn/lili/event/impl/RegisteredCouponActivityExecute.java @@ -1,18 +1,17 @@ package cn.lili.event.impl; +import cn.lili.cache.Cache; +import cn.lili.cache.CachePrefix; +import cn.lili.common.utils.StringUtils; import cn.lili.event.MemberRegisterEvent; import cn.lili.modules.member.entity.dos.Member; -import cn.lili.modules.promotion.entity.dos.CouponActivity; +import cn.lili.modules.member.service.MemberService; +import cn.lili.modules.promotion.entity.dto.CouponActivityTrigger; import cn.lili.modules.promotion.entity.enums.CouponActivityTypeEnum; -import cn.lili.modules.promotion.entity.enums.PromotionsStatusEnum; import cn.lili.modules.promotion.service.CouponActivityService; -import cn.lili.modules.promotion.tools.PromotionTools; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.List; - /** * 注册赠券活动 * @@ -25,6 +24,12 @@ public class RegisteredCouponActivityExecute implements MemberRegisterEvent { @Autowired private CouponActivityService couponActivityService; + + @Autowired + private MemberService memberService; + @Autowired + private Cache cache; + /** * 获取进行中的注册赠券的优惠券活动 * 发送注册赠券 @@ -33,9 +38,22 @@ public class RegisteredCouponActivityExecute implements MemberRegisterEvent { */ @Override public void memberRegister(Member member) { - List couponActivities = couponActivityService.list(new QueryWrapper() - .eq("coupon_activity_type", CouponActivityTypeEnum.REGISTERED.name()) - .and(PromotionTools.queryPromotionStatus(PromotionsStatusEnum.START))); - couponActivityService.registered(couponActivities, member); + //用户注册赠券 + couponActivityService.trigger(CouponActivityTrigger.builder() + .nickName(member.getNickName()) + .userId(member.getId()) + .couponActivityTypeEnum(CouponActivityTypeEnum.REGISTERED) + .build()); + //邀请人赠券 + String memberId = (String) cache.get(CachePrefix.INVITER.getPrefix() + member.getId()); + if (StringUtils.isNotEmpty(memberId)) { + //邀请人 + Member inviter = memberService.getById(memberId); + couponActivityService.trigger(CouponActivityTrigger.builder() + .nickName(inviter.getNickName()) + .userId(inviter.getId()) + .couponActivityTypeEnum(CouponActivityTypeEnum.INVITE_NEW) + .build()); + } } } 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/consumer/src/main/java/cn/lili/listener/MemberMessageListener.java b/consumer/src/main/java/cn/lili/listener/MemberMessageListener.java index ab767f10..2e384744 100644 --- a/consumer/src/main/java/cn/lili/listener/MemberMessageListener.java +++ b/consumer/src/main/java/cn/lili/listener/MemberMessageListener.java @@ -1,10 +1,8 @@ package cn.lili.listener; import cn.hutool.json.JSONUtil; -import cn.lili.event.MemberLoginEvent; -import cn.lili.event.MemberPointChangeEvent; -import cn.lili.event.MemberRegisterEvent; -import cn.lili.event.MemberWithdrawalEvent; +import cn.lili.event.*; +import cn.lili.event.impl.ImTalkExecute; import cn.lili.modules.member.entity.dos.Member; import cn.lili.modules.member.entity.dos.MemberSign; import cn.lili.modules.member.entity.dto.MemberPointMessage; @@ -58,6 +56,9 @@ public class MemberMessageListener implements RocketMQListener { @Autowired private List memberLoginEvents; + @Autowired + private List memberInfoChangeEvents; + @Override public void onMessage(MessageExt messageExt) { @@ -110,6 +111,20 @@ public class MemberMessageListener implements RocketMQListener { } } break; + //会员信息更改 + case MEMBER_INFO_EDIT: + for (MemberInfoChangeEvent memberInfoChangeEvent : memberInfoChangeEvents) { + try { + Member member = JSONUtil.toBean(new String(messageExt.getBody()), Member.class); + memberInfoChangeEvent.memberInfoChange(member); + } catch (Exception e) { + log.error("会员{},在{}业务中,提现事件执行异常", + new String(messageExt.getBody()), + memberInfoChangeEvent.getClass().getName(), + e); + } + } + break; //会员提现 case MEMBER_WITHDRAWAL: for (MemberWithdrawalEvent memberWithdrawalEvent : memberWithdrawalEvents) { diff --git a/consumer/src/main/java/cn/lili/listener/StoreMessageListener.java b/consumer/src/main/java/cn/lili/listener/StoreMessageListener.java new file mode 100644 index 00000000..243de85f --- /dev/null +++ b/consumer/src/main/java/cn/lili/listener/StoreMessageListener.java @@ -0,0 +1,51 @@ +package cn.lili.listener; + +import cn.hutool.json.JSONUtil; +import cn.lili.event.MemberRegisterEvent; +import cn.lili.event.StoreSettingChangeEvent; +import cn.lili.modules.member.entity.dos.Member; +import cn.lili.modules.store.entity.dos.Store; +import cn.lili.rocketmq.tags.StoreTagsEnum; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 店铺消息 + * @author chc + * @since 2022/6/2114:46 + */ +@Component +@Slf4j +@RocketMQMessageListener(topic = "${lili.data.rocketmq.store-topic}", consumerGroup = "${lili.data.rocketmq.store-group}") +public class StoreMessageListener implements RocketMQListener { + @Autowired + private List storeSettingChangeEventList; + + @Override + public void onMessage(MessageExt messageExt) { + switch (StoreTagsEnum.valueOf(messageExt.getTags())){ + //修改店铺 + case EDIT_STORE_SETTING: + for (StoreSettingChangeEvent storeSettingChangeEvent : storeSettingChangeEventList) { + try { + Store store = JSONUtil.toBean(new String(messageExt.getBody()), Store.class); + storeSettingChangeEvent.storeSettingChange(store); + } catch (Exception e) { + log.error("会员{},在{}业务中,状态修改事件执行异常", + new String(messageExt.getBody()), + storeSettingChangeEvent.getClass().getName(), + e); + } + } + break; + default: + break; + } + } +} diff --git a/consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/MemberCouponSignEverydayExecute.java b/consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/MemberCouponSignEverydayExecute.java new file mode 100644 index 00000000..13a5e7a3 --- /dev/null +++ b/consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/MemberCouponSignEverydayExecute.java @@ -0,0 +1,45 @@ +package cn.lili.timetask.handler.impl.promotion; + +import cn.lili.common.enums.PromotionTypeEnum; +import cn.lili.modules.promotion.entity.dos.Seckill; +import cn.lili.modules.promotion.service.MemberCouponSignService; +import cn.lili.modules.promotion.service.SeckillService; +import cn.lili.modules.promotion.tools.PromotionTools; +import cn.lili.modules.search.service.EsGoodsIndexService; +import cn.lili.modules.system.entity.dos.Setting; +import cn.lili.modules.system.entity.dto.SeckillSetting; +import cn.lili.modules.system.entity.enums.SettingEnum; +import cn.lili.modules.system.service.SettingService; +import cn.lili.timetask.handler.EveryDayExecute; +import com.google.gson.Gson; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 促销活动每日定时器 + * + * @author Chopper + * @since 2021/3/18 3:23 下午 + */ +@Slf4j +@Component +public class MemberCouponSignEverydayExecute implements EveryDayExecute { + + @Autowired + private MemberCouponSignService memberCouponSignService; + + /** + * 将已过期的促销活动置为结束 + */ + @Override + public void execute() { + try { + memberCouponSignService.clean(); + } catch (Exception e) { + log.error("清除领取优惠券标记异常", e); + } + + } + +} diff --git a/consumer/src/main/resources/application.yml b/consumer/src/main/resources/application.yml index ae49a9b8..f3c3ed20 100644 --- a/consumer/src/main/resources/application.yml +++ b/consumer/src/main/resources/application.yml @@ -260,6 +260,8 @@ lili: order-group: lili_order_group member-topic: lili_member_topic member-group: lili_member_group + store-topic: lili_store_topic + store-group: lili_store_group other-topic: lili_other_topic other-group: lili_other_group notice-topic: lili_notice_topic diff --git a/framework/pom.xml b/framework/pom.xml index da681cb3..5e0b4b74 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -51,7 +51,10 @@ - + + org.springframework.boot + spring-boot-starter-websocket + org.springframework.boot spring-boot-starter-web diff --git a/framework/src/main/java/cn/lili/cache/CachePrefix.java b/framework/src/main/java/cn/lili/cache/CachePrefix.java index bfa31f49..c1481c65 100644 --- a/framework/src/main/java/cn/lili/cache/CachePrefix.java +++ b/framework/src/main/java/cn/lili/cache/CachePrefix.java @@ -208,6 +208,10 @@ public enum CachePrefix { * 促销活动 */ PROMOTION, + /** + * 当前优惠券活动 + */ + CURRENT_COUPON_ACTIVITY, /** * 促销活动 */ @@ -236,6 +240,10 @@ public enum CachePrefix { * 积分商品缓存key前缀 */ STORE_ID_EXCHANGE, + /** + * 会员领取标记 + */ + MEMBER_COUPON_SIGN, //================交易================= @@ -441,6 +449,10 @@ public enum CachePrefix { * 分销员 */ DISTRIBUTION, + /** + * 邀请人 + */ + INVITER, /** * 找回手机 @@ -503,12 +515,11 @@ public enum CachePrefix { /** * 扫码登录 + * * @param str * @return */ - QR_CODE_LOGIN_SESSION - - ; + QR_CODE_LOGIN_SESSION; public static String removePrefix(String str) { diff --git a/framework/src/main/java/cn/lili/cache/impl/RedisCache.java b/framework/src/main/java/cn/lili/cache/impl/RedisCache.java index a5e8aeec..ac56702b 100644 --- a/framework/src/main/java/cn/lili/cache/impl/RedisCache.java +++ b/framework/src/main/java/cn/lili/cache/impl/RedisCache.java @@ -185,7 +185,7 @@ public class RedisCache implements Cache { public Long counter(Object key) { HyperLogLogOperations operations = redisTemplate.opsForHyperLogLog(); - //add 方法对应 PFADD 命令 + //add 方法对应 PFCOUNT 命令 return operations.size(key); } diff --git a/framework/src/main/java/cn/lili/common/enums/ResultCode.java b/framework/src/main/java/cn/lili/common/enums/ResultCode.java index 6acf99dd..7e7966c7 100644 --- a/framework/src/main/java/cn/lili/common/enums/ResultCode.java +++ b/framework/src/main/java/cn/lili/common/enums/ResultCode.java @@ -280,6 +280,7 @@ public enum ResultCode { PROMOTION_ACTIVITY_GOODS_ERROR(40009, "当前活动已经开始无法添加商品"), PROMOTION_ACTIVITY_ERROR(400010, "当前促销活动不存在"), PROMOTION_LOG_EXIST(40011, "活动已参加,已发重复参加"), + APPLY_END_TIME_ERROR(40012, "参与截至时间不能小于当前时间,不能大于活动开始时间"), /** * 优惠券 @@ -301,6 +302,7 @@ public enum ResultCode { COUPON_SCOPE_ERROR(41014, "指定商品范围关联id无效!"), COUPON_MEMBER_NOT_EXIST(41015, "没有当前会员优惠券"), COUPON_MEMBER_STATUS_ERROR(41016, "当前会员优惠券已过期/作废无法变更状态!"), + COUPON_RANGE_ERROR(41017, "优惠券使用时间范围错误"), SPECIAL_CANT_USE(41019, "特殊商品不能使用优惠券,不能使用"), @@ -308,7 +310,7 @@ public enum ResultCode { COUPON_DELETE_ERROR(41021, "删除优惠券失败"), COUPON_ACTIVITY_NOT_EXIST(41022, "当前优惠券活动不存在"), COUPON_ACTIVITY_SAVE_ERROR(41023, "保存优惠券活动失败"), - COUPON_ACTIVITY_MAX_NUM(41024, "优惠券活动赠券数量最多为3"), + COUPON_ACTIVITY_MAX_NUM(41024, "优惠券活动赠券数量最多为5"), COUPON_DO_NOT_RECEIVER(41030, "当前优惠券不允许主动领取"), @@ -373,6 +375,7 @@ public enum ResultCode { COUPON_ACTIVITY_ITEM_ERROR(46003, "优惠券活动必须指定优惠券,不能为空"), COUPON_ACTIVITY_ITEM_MUST_NUM_ERROR(46004, "优惠券活动最多指定10个优惠券"), COUPON_ACTIVITY_ITEM_NUM_ERROR(46005, "赠券数量必须大于0"), + COUPON_ACTIVITY_ITEM_NUM_MAX_VALUE_2(46006, "赠券数量最大为2"), /** * 其他促销 diff --git a/framework/src/main/java/cn/lili/common/security/AuthUser.java b/framework/src/main/java/cn/lili/common/security/AuthUser.java index f49f2051..819ae6e6 100644 --- a/framework/src/main/java/cn/lili/common/security/AuthUser.java +++ b/framework/src/main/java/cn/lili/common/security/AuthUser.java @@ -3,6 +3,7 @@ package cn.lili.common.security; import cn.lili.common.security.enums.UserEnums; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; @@ -10,6 +11,7 @@ import java.io.Serializable; * @author Chopper */ @Data +@NoArgsConstructor @AllArgsConstructor public class AuthUser implements Serializable { @@ -68,6 +70,12 @@ public class AuthUser implements Serializable { */ private Boolean isSuper = false; + /** + * 租户id + */ + private String tenantId; + + public AuthUser(String username, String id, String nickName, String face, UserEnums role) { this.username = username; this.face = face; @@ -85,7 +93,7 @@ public class AuthUser implements Serializable { this.nickName = nickName; } - public AuthUser(String username, String id, UserEnums manager, String nickName, Boolean isSuper, String clerkId,String face) { + public AuthUser(String username, String id, UserEnums manager, String nickName, Boolean isSuper, String clerkId, String face) { this.username = username; this.id = id; this.role = manager; diff --git a/framework/src/main/java/cn/lili/common/security/context/UserContext.java b/framework/src/main/java/cn/lili/common/security/context/UserContext.java index 78d3e5a6..a1c86cae 100644 --- a/framework/src/main/java/cn/lili/common/security/context/UserContext.java +++ b/framework/src/main/java/cn/lili/common/security/context/UserContext.java @@ -7,6 +7,7 @@ import cn.lili.common.exception.ServiceException; import cn.lili.common.security.AuthUser; import cn.lili.common.security.enums.SecurityEnum; import cn.lili.common.security.token.SecretKeyUtil; +import cn.lili.common.utils.StringUtils; import com.google.gson.Gson; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; @@ -101,4 +102,21 @@ public class UserContext { return null; } } + + + /** + * 写入邀请人信息 + */ + public static void settingInviter(String memberId, Cache cache) { + if (RequestContextHolder.getRequestAttributes() != null) { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + //邀请人id + String inviterId = request.getHeader(SecurityEnum.INVITER.getValue()); + if (StringUtils.isNotEmpty(inviterId)) { + cache.put(CachePrefix.INVITER.getPrefix() + memberId, inviterId); + } + } + } + + } diff --git a/framework/src/main/java/cn/lili/common/security/enums/SecurityEnum.java b/framework/src/main/java/cn/lili/common/security/enums/SecurityEnum.java index c89a3f4b..ad49e685 100644 --- a/framework/src/main/java/cn/lili/common/security/enums/SecurityEnum.java +++ b/framework/src/main/java/cn/lili/common/security/enums/SecurityEnum.java @@ -10,7 +10,7 @@ public enum SecurityEnum { /** * 存在与header中的token参数头 名 */ - HEADER_TOKEN("accessToken"), USER_CONTEXT("userContext"), JWT_SECRET("secret"), UUID("uuid"); + HEADER_TOKEN("accessToken"), USER_CONTEXT("userContext"), JWT_SECRET("secret"), UUID("uuid"), INVITER("inviter"); String value; diff --git a/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java b/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java index 07d86b64..919b6693 100644 --- a/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java +++ b/framework/src/main/java/cn/lili/common/security/enums/UserEnums.java @@ -14,7 +14,8 @@ public enum UserEnums { MEMBER("会员"), STORE("商家"), MANAGER("管理员"), - SYSTEM("系统"); + SYSTEM("系统"), + SEAT("坐席"); private final String role; UserEnums(String role) { 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..3b795d22 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,32 @@ 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 imRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .groupName("im") + .apiInfo(apiInfo()).select() + //扫描所有有注解的api,用这种方式更灵活 + .apis(RequestHandlerSelectors.basePackage("cn.lili.controller.im")) + .paths(PathSelectors.any()) + .build() + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()); + } @Bean public Docket memberRestApi() { diff --git a/framework/src/main/java/cn/lili/common/utils/DateUtil.java b/framework/src/main/java/cn/lili/common/utils/DateUtil.java index ec6c5ef4..1e0a10e7 100644 --- a/framework/src/main/java/cn/lili/common/utils/DateUtil.java +++ b/framework/src/main/java/cn/lili/common/utils/DateUtil.java @@ -26,15 +26,16 @@ public class DateUtil { * @return 今天开始时间 */ public static Long getDayOfStart() { - return DateUtil.getDateline()/(60*24*60); + return DateUtil.getDateline() / (60 * 24 * 60); } + /** * 指定日的开始时间 * * @return 指定日时间 */ public static Long getDayOfStart(Date date) { - return date.getTime()/(60*24*60); + return date.getTime() / (60 * 24 * 60); } /** @@ -349,6 +350,22 @@ public class DateUtil { return getDateline(mon, STANDARD_FORMAT); } + /** + * 获取当前天的结束时间 + * + * @return 当前天的开始时间 + */ + public static Date getCurrentDayStartTime() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) - 1); + return cal.getTime(); + } + /** * 获取当前天的结束时间 * @@ -366,6 +383,21 @@ public class DateUtil { return cal.getTime(); } + /** + * 获取干净的时间 + * + * @return 时间对象 + */ + public static Calendar getCleanCalendar() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal; + } + /** * 获取延时时间(秒) * diff --git a/framework/src/main/java/cn/lili/modules/connect/serviceimpl/ConnectServiceImpl.java b/framework/src/main/java/cn/lili/modules/connect/serviceimpl/ConnectServiceImpl.java index 942bf897..3b7a9577 100644 --- a/framework/src/main/java/cn/lili/modules/connect/serviceimpl/ConnectServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/connect/serviceimpl/ConnectServiceImpl.java @@ -246,7 +246,17 @@ public class ConnectServiceImpl extends ServiceImpl impl Member newMember = new Member("m" + phone, "111111", phone, params.getNickName(), params.getImage()); memberService.save(newMember); newMember = memberService.findByUsername(newMember.getUsername()); + + //判定有没有邀请人并且写入 + UserContext.settingInviter(newMember.getId(), cache); + bindMpMember(openId, unionId, newMember); + + + //判定有没有邀请人并且写入 + UserContext.settingInviter(newMember.getId(), cache); + + // 发送会员注册信息 applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("new member register", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_REGISTER.name(), newMember)); return memberTokenGenerate.createToken(newMember, true); diff --git a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java index c97c2d0d..8410e414 100644 --- a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/CategoryServiceImpl.java @@ -241,12 +241,7 @@ public class CategoryServiceImpl extends ServiceImpl i } } UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("id", category.getId()) - .set("name", category.getName()) - .set("image", category.getImage()) - .set("sort_order", category.getSortOrder()) - .set(DELETE_FLAG_COLUMN, category.getDeleteFlag()) - .set("commission_rate", category.getCommissionRate()); + updateWrapper.eq("id", category.getId()); this.baseMapper.update(category, updateWrapper); removeCache(); } diff --git a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java index cdfe4c3f..2cc364b1 100644 --- a/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/goods/serviceimpl/GoodsSkuServiceImpl.java @@ -327,7 +327,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl i //记录用户足迹 if (UserContext.getCurrentUser() != null) { - FootPrint footPrint = new FootPrint(UserContext.getCurrentUser().getId(), goodsId, skuId); + FootPrint footPrint = new FootPrint(UserContext.getCurrentUser().getId(), goodsIndex.getStoreId(), goodsId, skuId); String destination = rocketmqCustomProperties.getGoodsTopic() + ":" + GoodsTagsEnum.VIEW_GOODS.name(); rocketMQTemplate.asyncSend(destination, footPrint, RocketmqSendCallbackBuilder.commonCallback()); } diff --git a/framework/src/main/java/cn/lili/modules/im/config/CustomSpringConfigurator.java b/framework/src/main/java/cn/lili/modules/im/config/CustomSpringConfigurator.java new file mode 100644 index 00000000..d9f825c0 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/config/CustomSpringConfigurator.java @@ -0,0 +1,34 @@ +package cn.lili.modules.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/modules/im/config/WebSocketConfigurator.java b/framework/src/main/java/cn/lili/modules/im/config/WebSocketConfigurator.java new file mode 100644 index 00000000..c6de471b --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/config/WebSocketConfigurator.java @@ -0,0 +1,24 @@ +package cn.lili.modules.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/modules/im/entity/dos/ImMessage.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImMessage.java new file mode 100644 index 00000000..f381faca --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImMessage.java @@ -0,0 +1,69 @@ +package cn.lili.modules.im.entity.dos; + +import cn.lili.common.utils.SnowFlake; +import cn.lili.modules.im.entity.enums.MessageTypeEnum; +import cn.lili.modules.im.entity.vo.MessageOperation; +import cn.lili.mybatis.BaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author Chopper + */ +@Data +@TableName("li_im_message") +@ApiModel(value = "Im消息") +@NoArgsConstructor +@AllArgsConstructor +public class ImMessage extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 发送者 + */ + private String fromUser; + + /** + * 接收者 + */ + private String toUser; + + /** + * 已阅 + */ + private Boolean isRead; + + /** + * 消息类型 + */ + private MessageTypeEnum messageType; + + /** + * 聊天id + */ + private String talkId; + + /** + * 消息实体 + */ + private String text; + + + public ImMessage(MessageOperation messageOperation){ + this.setFromUser(messageOperation.getFrom()); + this.setMessageType(messageOperation.getMessageType()); + this.setIsRead(false); + this.setText(messageOperation.getContext()); + this.setTalkId(messageOperation.getTalkId()); + this.setCreateTime(new Date()); + this.setToUser(messageOperation.getTo()); + this.setId(SnowFlake.getIdStr()); + } + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/ImTalk.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImTalk.java new file mode 100644 index 00000000..56ffe258 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/ImTalk.java @@ -0,0 +1,102 @@ +package cn.lili.modules.im.entity.dos; + + +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.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * @author Chopper + */ +@Data +@TableName("li_im_talk") +@ApiModel(value = "聊天") +@NoArgsConstructor +@AllArgsConstructor +public class ImTalk extends BaseTenantEntity { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("用户1 id") + private String userId1; + + @ApiModelProperty("用户2 id") + private String userId2; + + @ApiModelProperty("用户1置顶") + private Boolean top1; + + @ApiModelProperty("用户2置顶") + private Boolean top2; + + @ApiModelProperty("用户1 不可见") + private Boolean disable1; + + @ApiModelProperty("用户2 不可见") + private Boolean disable2; + + @ApiModelProperty("用户1名字") + private String name1; + + @ApiModelProperty("用户2名字") + private String name2; + + @ApiModelProperty("用户1头像") + private String face1; + + @ApiModelProperty("用户2头像") + private String face2; + + @ApiModelProperty("用户1的店铺标识") + private Boolean storeFlag1; + + @ApiModelProperty("用户2的店铺标识") + private Boolean storeFlag2; + + @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; + + @ApiModelProperty(value = "最后聊天内容") + private String lastTalkMessage; + + @ApiModelProperty(value = "最后发送消息类型") + private String lastMessageType; + + @ApiModelProperty(value = "坐席Id") + private String tenantId; + + @ApiModelProperty(value = "坐席名称") + private String tenantName; + + + 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.storeFlag1 = false; + this.storeFlag2 = 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/modules/im/entity/dos/QA.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/QA.java new file mode 100644 index 00000000..0d6bd3f2 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/QA.java @@ -0,0 +1,31 @@ +package cn.lili.modules.im.entity.dos; + +import cn.lili.mybatis.BaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 问题答案 + * + * @author Chopper + * @version v1.0 + * 2022-02-09 17:59 + */ +@Data +@TableName("li_qa") +@ApiModel(value = "租户问答") +@NoArgsConstructor +public class QA extends BaseEntity { + + @ApiModelProperty(value = "租户id") + private Integer tenantId; + + @ApiModelProperty(value = "问题") + private String question; + + @ApiModelProperty(value = "答案") + private String answer; +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/Seat.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/Seat.java new file mode 100644 index 00000000..40bdfd84 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/Seat.java @@ -0,0 +1,47 @@ +package cn.lili.modules.im.entity.dos; + +import cn.lili.mybatis.BaseTenantEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +/** + * 坐席 + * + * @author Chopper + * @version v1.0 + * 2022-02-09 17:08 + */ +@Data +@TableName("li_seat") +@ApiModel(value = "坐席") +@NoArgsConstructor +public class Seat extends BaseTenantEntity { + + @ApiModelProperty(value = "租户id") + private String tenantId; + + @ApiModelProperty(value = "坐席用户名") + private String username; + + @ApiModelProperty(value = "会员头像") + private String face; + + @ApiModelProperty(value = "坐席密码") + private String password; + + @ApiModelProperty(value = "昵称") + private String nickName; + + @ApiModelProperty(value = "坐席状态") + private Boolean disabled; + + @NotEmpty(message = "手机号码不能为空") + @ApiModelProperty(value = "手机号码", required = true) + private String mobile; + +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dos/SeatSetting.java b/framework/src/main/java/cn/lili/modules/im/entity/dos/SeatSetting.java new file mode 100644 index 00000000..a462ce7e --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dos/SeatSetting.java @@ -0,0 +1,36 @@ +package cn.lili.modules.im.entity.dos; + +import cn.lili.mybatis.BaseTenantEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 坐席设置 + * + * @author Chopper + * @version v1.0 + * 2022-02-09 17:55 + */ +@Data +@TableName("li_seat_setting") +@ApiModel(value = "坐席设置") +@NoArgsConstructor +public class SeatSetting extends BaseTenantEntity { + + @ApiModelProperty(value = "租户idid") + private String tenantId; + + @ApiModelProperty(value = "欢迎语") + private String welcome; + + @ApiModelProperty(value = "离线自动回复") + private String outLineAutoReply; + + @ApiModelProperty(value = "长时间自动回复") + private String longTermAutoReply; + + +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dto/ImQueryParams.java b/framework/src/main/java/cn/lili/modules/im/entity/dto/ImQueryParams.java new file mode 100644 index 00000000..8dc1f0fa --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dto/ImQueryParams.java @@ -0,0 +1,36 @@ +package cn.lili.modules.im.entity.dto; + +import cn.hutool.core.text.CharSequenceUtil; +import cn.lili.common.vo.PageVO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author chc + * @since 2022/6/2114:46 + */ +@Data +@ApiModel +public class ImQueryParams extends PageVO { + + @ApiModelProperty("用户Id") + private String memberId; + + @ApiModelProperty("店铺Id") + private String storeId; + + public QueryWrapper queryWrapper() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (CharSequenceUtil.isNotEmpty(memberId)) { + queryWrapper.eq("member_id", memberId); + } + if (CharSequenceUtil.isNotEmpty(storeId)) { + queryWrapper.eq("store_id", storeId); + } + queryWrapper.eq("delete_flag",false); + queryWrapper.orderByDesc("create_time"); + return queryWrapper; + } +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/dto/MessageQueryParams.java b/framework/src/main/java/cn/lili/modules/im/entity/dto/MessageQueryParams.java new file mode 100644 index 00000000..372522c1 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/dto/MessageQueryParams.java @@ -0,0 +1,50 @@ +package cn.lili.modules.im.entity.dto; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.utils.StringUtils; +import cn.lili.common.vo.PageVO; +import cn.lili.modules.im.entity.dos.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 extends PageVO { + /** + * 聊天窗口 + */ + 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::getCreateTime); +// lambdaQueryWrapper.last("limit " + num); + return lambdaQueryWrapper; + } +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageResultType.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageResultType.java new file mode 100644 index 00000000..ba54b5d5 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageResultType.java @@ -0,0 +1,28 @@ +package cn.lili.modules.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/modules/im/entity/enums/MessageStatusEnum.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java new file mode 100644 index 00000000..687c814c --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageStatusEnum.java @@ -0,0 +1,31 @@ +package cn.lili.modules.im.entity.enums; + +/** + * 消息的类型 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2022/2/10 16:36 + */ +public enum MessageStatusEnum { + //socket刚打开时发送的消息,这个一般是是刚打开socket链接,进行登录,传入token用 + CONNECT, + //心跳类型的消息,此种类型的消息只有 type 、 text 两种属性 + HEARTBEAT, + //用户打开一个对话框,准备跟某人聊天时 + OPEN, + //客服进行自动回复。客户端发起这种类型请求,则是在拉取对方是否有自动回复,如果有,服务端就会给客户端发送过自动回复的信息 + AUTO_REPLY, + //正常收发消息沟通,文字、表情等沟通 + MSG, + //扩展。比如发送商品、发送订单 + EXTEND, + //系统提示,如提示 对方已离线 + SYSTEM, + //服务端发送到客户端,用于设置客户端的用户信息。会吧 com.xnx3.yunkefu.core.vo.bean.User 传过去 + SET_USER, + //结束服务 + CLOSE_SERVICE; + +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java new file mode 100644 index 00000000..6b06d3b7 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/MessageTypeEnum.java @@ -0,0 +1,23 @@ +package cn.lili.modules.im.entity.enums; + +/** + * 消息类型 + * + * @author liushuai + */ +public enum MessageTypeEnum { + /** + * 消息类型枚举 + *

+ * 普通消息 + * 图片 + * 语音 + * 视频 + */ + MESSAGE, + PICTURE, + VOICE, + GOODS, + ORDER, + VIDEO +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/OnlineStatusEnum.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/OnlineStatusEnum.java new file mode 100644 index 00000000..837a4493 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/OnlineStatusEnum.java @@ -0,0 +1,14 @@ +package cn.lili.modules.im.entity.enums; + +/** + * 坐席在线状态 + * + * @author Chopper + * @version v1.0 + * 2022-02-10 16:37 + */ +public enum OnlineStatusEnum { + // 在线/下线 + ONLINE, + OUTLINE; +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java b/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java new file mode 100644 index 00000000..5909222e --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/enums/OperationType.java @@ -0,0 +1,26 @@ +package cn.lili.modules.im.entity.enums; + +/** + * 操作类型枚举 + * + * @author liushuai + */ +public enum OperationType { + /** + * 消息类型枚举 + *

+ * 心跳检测 + * 发起聊天 + * 发起消息 + * 查询历史消息 + * 阅读消息 + * 查询未读消息 + */ + PING, + CREATE, + MESSAGE, + HISTORY, + READ, + UNREAD, + +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java new file mode 100644 index 00000000..6d80a8be --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ImTalkVO.java @@ -0,0 +1,82 @@ +package cn.lili.modules.im.entity.vo; + +import cn.lili.modules.im.entity.dos.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; + + @ApiModelProperty("id") + private String id; + + @ApiModelProperty("用户 id") + private String userId; + + @ApiModelProperty("置顶") + private Boolean top; + + @ApiModelProperty("用户 不可见") + private Boolean disable; + + @ApiModelProperty("用户名字") + private String name; + + @ApiModelProperty("用户头像") + private String face; + + @ApiModelProperty("店铺标识") + private Boolean storeFlag; + + @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; + + @ApiModelProperty(value = "最后聊天内容") + private String lastTalkMessage; + + @ApiModelProperty(value = "最后发送消息类型") + private String lastMessageType; + + @ApiModelProperty(value = "未读数量") + private Long unread; + + 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(); + storeFlag = imTalk.getStoreFlag1(); + } else { + userId = imTalk.getUserId2(); + top = imTalk.getTop2(); + disable = imTalk.getDisable2(); + name = imTalk.getName2(); + face = imTalk.getFace2(); + storeFlag = imTalk.getStoreFlag2(); + } + lastTalkMessage = imTalk.getLastTalkMessage(); + lastTalkTime = imTalk.getLastTalkTime(); + lastMessageType = imTalk.getLastMessageType(); + id = imTalk.getId(); + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java new file mode 100644 index 00000000..b4360bc6 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageOperation.java @@ -0,0 +1,53 @@ +package cn.lili.modules.im.entity.vo; + +import cn.lili.common.utils.StringUtils; +import cn.lili.modules.im.entity.enums.MessageTypeEnum; +import cn.lili.modules.im.entity.enums.OperationType; +import lombok.Data; + +/** + * @author liushuai + */ +@Data +public class MessageOperation { + + /** + * 消息类型 + */ + private OperationType operationType; + /** + * 与某人聊天记录 + */ + private String to; + + /** + * 发送者 + */ + private String from; + + /** + * 聊天id + */ + private String talkId; + + /** + * 消息类型 + */ + private MessageTypeEnum 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 = MessageTypeEnum.valueOf(messageType); + } + } +} diff --git a/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageVO.java new file mode 100644 index 00000000..420091e1 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/MessageVO.java @@ -0,0 +1,26 @@ +package cn.lili.modules.im.entity.vo; + +import cn.lili.modules.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/modules/im/entity/vo/ReadMessage.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/ReadMessage.java new file mode 100644 index 00000000..bbeb7d11 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/ReadMessage.java @@ -0,0 +1,17 @@ +package cn.lili.modules.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/modules/im/entity/vo/SeatVO.java b/framework/src/main/java/cn/lili/modules/im/entity/vo/SeatVO.java new file mode 100644 index 00000000..d1df9d1c --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/entity/vo/SeatVO.java @@ -0,0 +1,22 @@ +package cn.lili.modules.im.entity.vo; + +import cn.lili.modules.im.entity.dos.Seat; +import lombok.Data; + +/** + * 客服VO + * + * @author Chopper + * @version v1.0 + * 2022-02-10 15:02 + */ +@Data +public class SeatVO extends Seat { + + /** + * 在线状态 + */ + private String onlineStatus; + + +} diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/ImMessageMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImMessageMapper.java new file mode 100644 index 00000000..e82b0cac --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImMessageMapper.java @@ -0,0 +1,12 @@ +package cn.lili.modules.im.mapper; + +import cn.lili.modules.im.entity.dos.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/modules/im/mapper/ImTalkMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/ImTalkMapper.java new file mode 100644 index 00000000..d5f0d2b1 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/ImTalkMapper.java @@ -0,0 +1,12 @@ +package cn.lili.modules.im.mapper; + +import cn.lili.modules.im.entity.dos.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/modules/im/mapper/QAMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/QAMapper.java new file mode 100644 index 00000000..f5592316 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/QAMapper.java @@ -0,0 +1,16 @@ +package cn.lili.modules.im.mapper; + + +import cn.lili.modules.im.entity.dos.QA; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 问答处理层 + * + * @author pikachu + * @since 2020-02-18 15:18:56 + */ +public interface QAMapper extends BaseMapper { + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/SeatMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/SeatMapper.java new file mode 100644 index 00000000..98d7b6ae --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/SeatMapper.java @@ -0,0 +1,16 @@ +package cn.lili.modules.im.mapper; + + +import cn.lili.modules.im.entity.dos.Seat; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 坐席处理层 + * + * @author pikachu + * @since 2020-02-18 15:18:56 + */ +public interface SeatMapper extends BaseMapper { + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/mapper/SeatSettingMapper.java b/framework/src/main/java/cn/lili/modules/im/mapper/SeatSettingMapper.java new file mode 100644 index 00000000..9e130ef3 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/mapper/SeatSettingMapper.java @@ -0,0 +1,16 @@ +package cn.lili.modules.im.mapper; + + +import cn.lili.modules.im.entity.dos.SeatSetting; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 坐席设置处理层 + * + * @author pikachu + * @since 2020-02-18 15:18:56 + */ +public interface SeatSettingMapper extends BaseMapper { + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java b/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java new file mode 100644 index 00000000..57fee7cc --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/ImMessageService.java @@ -0,0 +1,63 @@ +package cn.lili.modules.im.service; + +import cn.lili.modules.im.entity.dos.ImMessage; +import cn.lili.modules.im.entity.dto.MessageQueryParams; +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); + + /** + * 分页获取消息列表 + * @param messageQueryParams 查询条件 + * @return 消息列表 + */ + List getList(MessageQueryParams messageQueryParams); + + /** + * 获取所有未读消息 + * @return + */ + Long unreadMessageCount(); + + /** + * 清空所有未读消息 + */ + void cleanUnreadMessage(); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/ImTalkService.java b/framework/src/main/java/cn/lili/modules/im/service/ImTalkService.java new file mode 100644 index 00000000..427750fd --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/ImTalkService.java @@ -0,0 +1,51 @@ +package cn.lili.modules.im.service; + +import cn.lili.modules.im.entity.dos.ImTalk; +import cn.lili.modules.im.entity.vo.ImTalkVO; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + * 聊天 业务层 + * + * @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); + + /** + * 获取用户聊天列表 + * @return + */ + List getUserTalkList(String userName); + + /** + * 获取商家聊天列表 + * @return + */ + List getStoreTalkList(); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/QAService.java b/framework/src/main/java/cn/lili/modules/im/service/QAService.java new file mode 100644 index 00000000..49f8572b --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/QAService.java @@ -0,0 +1,25 @@ +package cn.lili.modules.im.service; + + +import cn.lili.common.vo.PageVO; +import cn.lili.modules.im.entity.dos.QA; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 问答 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +public interface QAService extends IService { + + /** + * 查询店铺问题 + * @param word + * @param pageVO + * @return + */ + IPage getStoreQA(String word, PageVO pageVO); + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/SeatService.java b/framework/src/main/java/cn/lili/modules/im/service/SeatService.java new file mode 100644 index 00000000..b0cf8eac --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/SeatService.java @@ -0,0 +1,60 @@ +package cn.lili.modules.im.service; + + +import cn.lili.common.security.token.Token; +import cn.lili.modules.im.entity.dos.Seat; +import cn.lili.modules.im.entity.vo.SeatVO; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + * 坐席业务 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +public interface SeatService extends IService { + + + /** + * 获取坐席列表 + * + * @param storeId 店铺id + * @return + */ + List seatVoList(String storeId); + + /** + * 坐席登录 + * + * @param username + * @param password + * @return + */ + Token usernameLogin(String username, String password); + + /** + * 快捷登录code 生成 + * + * @param username 用户名 + * @return + */ + String createQuickLoginCode(String username); + + /** + * 快捷登录 + * + * @param code + * @return + */ + Token quickLogin(String code); + + /** + * 查询坐席 + * + * @param username + * @return + */ + Seat findByUsername(String username); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/service/SeatSettingService.java b/framework/src/main/java/cn/lili/modules/im/service/SeatSettingService.java new file mode 100644 index 00000000..364ba10f --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/service/SeatSettingService.java @@ -0,0 +1,30 @@ +package cn.lili.modules.im.service; + +import cn.lili.modules.im.entity.dos.SeatSetting; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 坐席设置业务 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +public interface SeatSettingService extends IService { + + + /** + * 根据店铺id获取坐席配置 + * + * @param storeId + * @return + */ + SeatSetting getSetting(String storeId); + + /** + * 根据店铺修改坐席设置 + * + * @param seatSetting 坐席设置 + * @return + */ + SeatSetting updateByStore(SeatSetting seatSetting); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java new file mode 100644 index 00000000..c216c282 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImMessageServiceImpl.java @@ -0,0 +1,143 @@ +package cn.lili.modules.im.serviceimpl; + +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.modules.im.entity.dos.ImMessage; +import cn.lili.modules.im.entity.dto.MessageQueryParams; +import cn.lili.modules.im.mapper.ImMessageMapper; +import cn.lili.modules.im.service.ImMessageService; +import cn.lili.modules.im.service.ImTalkService; +import cn.lili.mybatis.util.PageUtil; +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.ArrayList; +import java.util.Comparator; +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; + + } + + @Override + public List getList(MessageQueryParams messageQueryParams) { + List messageList = this.page(PageUtil.initPage(messageQueryParams), messageQueryParams.initQueryWrapper()).getRecords(); + ListSort(messageList); + readMessage(messageList); + return messageList; + } + + @Override + public Long unreadMessageCount() { + AuthUser currentUser = UserContext.getCurrentUser(); + if(currentUser == null){ + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + return this.count(new LambdaQueryWrapper().eq(ImMessage::getToUser,currentUser.getId()).eq(ImMessage::getIsRead,false)); + } + + @Override + public void cleanUnreadMessage() { + AuthUser currentUser = UserContext.getCurrentUser(); + if(currentUser == null){ + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + this.update(new LambdaUpdateWrapper().eq(ImMessage::getToUser,currentUser.getId()).set(ImMessage::getIsRead,true)); + } + + /** + * 根据时间倒叙 + * + * @param list + */ + private static void ListSort(List list) { + list.sort(new Comparator() { + @Override + public int compare(ImMessage e1, ImMessage e2) { + try { + if (e1.getCreateTime().before(e2.getCreateTime())) { + return -1; + } else { + return 1; + } + } catch (Exception e) { + e.printStackTrace(); + } + return 0; + } + }); + } + + + /** + * 阅读消息 + * + * @param messageList 消息列表 + */ + private void readMessage(List messageList) { + if (messageList.size() > 0) { + for (ImMessage imMessage : messageList) { + if(Boolean.FALSE.equals(imMessage.getIsRead())){ + imMessage.setIsRead(true); + } + } + } + this.updateBatchById(messageList); + } + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImTalkServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImTalkServiceImpl.java new file mode 100644 index 00000000..2b24c8bb --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/ImTalkServiceImpl.java @@ -0,0 +1,187 @@ +package cn.lili.modules.im.serviceimpl; + +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.modules.im.entity.dos.ImMessage; +import cn.lili.modules.im.entity.dos.ImTalk; +import cn.lili.modules.im.entity.vo.ImTalkVO; +import cn.lili.modules.im.mapper.ImTalkMapper; +import cn.lili.modules.im.service.ImMessageService; +import cn.lili.modules.im.service.ImTalkService; +import cn.lili.modules.member.entity.dos.Member; +import cn.lili.modules.member.service.MemberService; +import cn.lili.modules.store.entity.dos.Store; +import cn.lili.modules.store.service.StoreService; +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; +import org.stringtemplate.v4.ST; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 聊天 业务实现 + * + * @author Chopper + */ +@Service +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ImTalkServiceImpl extends ServiceImpl implements ImTalkService { + + @Autowired + private MemberService memberService; + + @Autowired + private StoreService storeService; + + @Autowired + private ImMessageService imMessageService; + + @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); + AuthUser currentUser = UserContext.getCurrentUser(); + //如果没有聊天,则创建聊天 + if (imTalk == null) { + // 没有登录的这个账户信息 + if (currentUser == null) { + return null; + } + //当自己为店铺时 + if(UserEnums.STORE.equals(currentUser.getRole())){ + Store selfStore = storeService.getById(userId1); + //没有这个用户信息 + Member other = memberService.getById(userId2); + if(other == null){ + return null; + } + //自己为店铺其他人必定为用户 + imTalk = new ImTalk(userId1, userId2, selfStore.getStoreLogo(), other.getFace(), selfStore.getStoreName(), other.getNickName()); + imTalk.setStoreFlag1(true); + }else if(UserEnums.MEMBER.equals(currentUser.getRole())){ + //没有这个店铺信息 + Member self = memberService.getById(userId1); + Member otherMember = memberService.getById(userId2); + Store otherStore = storeService.getById(userId2); + if(otherStore != null){ + imTalk = new ImTalk(userId1, userId2, self.getFace(), otherStore.getStoreLogo(), self.getNickName(), otherStore.getStoreName()); + imTalk.setStoreFlag2(true); + }else if (otherMember != null){ + imTalk = new ImTalk(userId1, userId2, self.getFace(), otherMember.getFace(), self.getNickName(), otherMember.getNickName()); + }else{ + return null; + } + } + 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); + } + } + + @Override + public List getUserTalkList(String userName) { + AuthUser authUser = UserContext.getCurrentUser(); + if(authUser == null){ + throw new ServiceException(ResultCode.USER_NOT_LOGIN); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.and(wq->{ + wq.like(ImTalk::getName1, userName).or().like(ImTalk::getName2,userName); + }); + queryWrapper.and(wq->{ + wq.like(ImTalk::getUserId1, authUser.getId()).or().like(ImTalk::getUserId2,authUser.getId()); + }); + queryWrapper.orderByDesc(ImTalk::getLastTalkTime); + List imTalks = this.list(queryWrapper); + List imTalkVOList = imTalks.stream().map(imTalk -> { + return new ImTalkVO(imTalk, authUser.getId()); + }).collect(Collectors.toList()); + getUnread(imTalkVOList); + return imTalkVOList; + } + + @Override + public List getStoreTalkList() { + AuthUser authUser = UserContext.getCurrentUser(); + if(authUser == null){ + throw new ServiceException(ResultCode.STORE_NOT_LOGIN_ERROR); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.and(wq->{ + wq.like(ImTalk::getUserId1, authUser.getStoreId()).or().like(ImTalk::getUserId2,authUser.getStoreId()); + }); + queryWrapper.orderByDesc(ImTalk::getLastTalkTime); + List imTalks = this.list(queryWrapper); + + List imTalkVOList = imTalks.stream().map(imTalk -> { + return new ImTalkVO(imTalk, authUser.getStoreId()); + }).collect(Collectors.toList()); + getUnread(imTalkVOList); + return imTalkVOList; + } + + /** + * 获取未读消息数量 + * @param imTalkVOList + */ + private void getUnread(List imTalkVOList){ + if(imTalkVOList.size() > 0){ + for (ImTalkVO imTalkVO : imTalkVOList) { + long count = imMessageService.count(new LambdaQueryWrapper().eq(ImMessage::getFromUser, imTalkVO.getUserId()).eq(ImMessage::getIsRead, false)); + imTalkVO.setUnread(count); + } + } + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/QAServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/QAServiceImpl.java new file mode 100644 index 00000000..2ee78fbc --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/QAServiceImpl.java @@ -0,0 +1,32 @@ +package cn.lili.modules.im.serviceimpl; + +import cn.lili.common.security.context.UserContext; +import cn.lili.common.vo.PageVO; +import cn.lili.modules.im.entity.dos.QA; +import cn.lili.modules.im.mapper.QAMapper; +import cn.lili.modules.im.service.QAService; +import cn.lili.mybatis.util.PageUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 坐席业务层实现 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class QAServiceImpl extends ServiceImpl implements QAService { + + @Override + public IPage getStoreQA(String word, PageVO pageVo) { + LambdaQueryWrapper qaLambdaQueryWrapper = new LambdaQueryWrapper<>(); + qaLambdaQueryWrapper.eq(QA::getTenantId, UserContext.getCurrentUser().getTenantId()); + qaLambdaQueryWrapper.like(QA::getQuestion, word); + return this.page(PageUtil.initPage(pageVo), qaLambdaQueryWrapper); + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatServiceImpl.java new file mode 100644 index 00000000..cac28af1 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatServiceImpl.java @@ -0,0 +1,111 @@ +package cn.lili.modules.im.serviceimpl; + +import cn.lili.cache.Cache; +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.token.Token; +import cn.lili.common.utils.StringUtils; +import cn.lili.modules.im.entity.dos.Seat; +import cn.lili.modules.im.entity.enums.OnlineStatusEnum; +import cn.lili.modules.im.entity.vo.SeatVO; +import cn.lili.modules.im.mapper.SeatMapper; +import cn.lili.modules.im.service.SeatService; +import cn.lili.modules.im.token.SeatTokenGenerate; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * 坐席业务层实现 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class SeatServiceImpl extends ServiceImpl implements SeatService { + + + @Autowired + private SeatTokenGenerate seatTokenGenerate; + + @Autowired + private Cache cache; + + /** + * 快捷登录缓存前缀 + */ + private static String prefix = "{quick_login}_"; + + + @Override + public List seatVoList(String storeId) { + + LambdaQueryWrapper seatLambdaQueryWrapper = new LambdaQueryWrapper<>(); + seatLambdaQueryWrapper.eq(Seat::getTenantId, storeId); + List list = this.list(seatLambdaQueryWrapper); + + //转换模型为VO + List results = list.stream().map(item -> (SeatVO) item).collect(Collectors.toList()); + //填充坐席当前状态 + //todo + results.forEach(item -> { + item.setOnlineStatus(OnlineStatusEnum.ONLINE.name()); + }); + return results; + } + + @Override + public Token usernameLogin(String username, String password) { + + Seat seat = this.findByUsername(username); + //判断用户是否存在 + if (seat == null || !seat.getDisabled()) { + throw new ServiceException(ResultCode.ERROR); + } + //判断密码是否输入正确 + if (!new BCryptPasswordEncoder().matches(password, seat.getPassword())) { + throw new ServiceException(ResultCode.ERROR); + } + return seatTokenGenerate.createToken(seat, true); + } + + @Override + public String createQuickLoginCode(String username) { + String code = UUID.randomUUID().toString(); + cache.put(prefix + code, username, 20L); + return code; + } + + @Override + public Token quickLogin(String code) { + String username = cache.get(prefix + code); + cache.remove(prefix + code); + if (StringUtils.isEmpty(username)) { + throw new ServiceException(ResultCode.ERROR); + } + return seatTokenGenerate.createToken(findByUsername(username), true); + } + + /** + * 查询坐席 + * + * @param username + * @return + */ + @Override + public Seat findByUsername(String username) { + LambdaQueryWrapper seatLambdaQueryWrapper = new LambdaQueryWrapper<>(); + seatLambdaQueryWrapper.eq(Seat::getUsername, username); + return this.getOne(seatLambdaQueryWrapper); + } + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatSettingServiceImpl.java b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatSettingServiceImpl.java new file mode 100644 index 00000000..e5ec4a8e --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/serviceimpl/SeatSettingServiceImpl.java @@ -0,0 +1,48 @@ +package cn.lili.modules.im.serviceimpl; + +import cn.lili.common.enums.ResultCode; +import cn.lili.common.exception.ServiceException; +import cn.lili.modules.im.entity.dos.SeatSetting; +import cn.lili.modules.im.mapper.SeatSettingMapper; +import cn.lili.modules.im.service.SeatSettingService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 坐席设置业务层实现 + * + * @author pikachu + * @since 2020-02-18 16:18:56 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class SeatSettingServiceImpl extends ServiceImpl implements SeatSettingService { + @Override + public SeatSetting getSetting(String storeId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SeatSetting::getTenantId, storeId); + SeatSetting seatSetting = this.baseMapper.selectOne(queryWrapper); + if (seatSetting == null) { + seatSetting = new SeatSetting(); + seatSetting.setOutLineAutoReply("您好,我现在不在线,请您留下关键内容和联系方式,我看到后会立马回电。"); + seatSetting.setLongTermAutoReply("您好,我正在查阅相关资料,请您稍等。"); + seatSetting.setWelcome("您好,请问有什么可以帮您?"); + seatSetting.setTenantId(storeId); + this.save(seatSetting); + } + return seatSetting; + } + + @Override + public SeatSetting updateByStore(SeatSetting seatSetting) { + SeatSetting oldSetting = this.baseMapper.selectById(seatSetting.getId()); + if (oldSetting.getTenantId().equals(seatSetting.getTenantId())) { + this.updateById(seatSetting); + } else { + throw new ServiceException(ResultCode.ERROR); + } + return seatSetting; + } +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/im/token/SeatTokenGenerate.java b/framework/src/main/java/cn/lili/modules/im/token/SeatTokenGenerate.java new file mode 100644 index 00000000..482bcded --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/im/token/SeatTokenGenerate.java @@ -0,0 +1,42 @@ +package cn.lili.modules.im.token; + +import cn.lili.common.security.AuthUser; +import cn.lili.common.security.enums.UserEnums; +import cn.lili.common.security.token.Token; +import cn.lili.common.security.token.TokenUtil; +import cn.lili.common.security.token.base.AbstractTokenGenerate; +import cn.lili.modules.im.entity.dos.Seat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 会员token生成 + * + * @author Chopper + * @version v4.0 + * @since 2020/11/16 10:50 + */ +@Component +public class SeatTokenGenerate extends AbstractTokenGenerate { + @Autowired + private TokenUtil tokenUtil; + + @Override + public Token createToken(Seat seat, Boolean longTerm) { + AuthUser authUser = new AuthUser( + seat.getUsername(), + seat.getId(), + seat.getNickName(), + seat.getFace(), + UserEnums.SEAT); + authUser.setTenantId(seat.getTenantId()); + //登陆成功生成token + return tokenUtil.createToken(seat.getUsername(), authUser, longTerm, UserEnums.SEAT); + } + + @Override + public Token refreshToken(String refreshToken) { + return tokenUtil.refreshToken(refreshToken, UserEnums.SEAT); + } + +} diff --git a/framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java b/framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java index 2e8c1efd..23b4eba8 100644 --- a/framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/kdBrid/serviceImpl/KdNiaoServiceImpl.java @@ -26,7 +26,7 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.google.gson.Gson; -import groovy.util.logging.Slf4j; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -88,7 +88,7 @@ public class KdNiaoServiceImpl implements KdNiaoService { @Override - @OrderLogPoint(description = "'订单['+#orderSn+']发货,发货单号['+#logisticsNo+'],已打印电子面单'", orderSn = "#orderSn") + @OrderLogPoint(description = "'订单['+#orderSn+']发货,打印电子面单'", orderSn = "#orderSn") @Transactional(rollbackFor = Exception.class) public String createElectronicsFaceSheet(String orderSn, String logisticsId) throws Exception { //电子面单模板 @@ -198,6 +198,7 @@ public class KdNiaoServiceImpl implements KdNiaoService { //根据公司业务处理返回的信息...... JSONObject obj = JSONObject.parseObject(result); + log.info("电子面单响应:{}",result); if(!"100".equals(obj.getString("ResultCode"))){ return obj.getString("Reason"); } diff --git a/framework/src/main/java/cn/lili/modules/member/entity/dos/FootPrint.java b/framework/src/main/java/cn/lili/modules/member/entity/dos/FootPrint.java index 7b42ea3f..ed32fb2f 100644 --- a/framework/src/main/java/cn/lili/modules/member/entity/dos/FootPrint.java +++ b/framework/src/main/java/cn/lili/modules/member/entity/dos/FootPrint.java @@ -28,6 +28,9 @@ public class FootPrint extends BaseEntity { @ApiModelProperty(value = "会员ID") private String memberId; + @ApiModelProperty(value = "店铺Id") + private String storeId; + @ApiModelProperty(value = "商品ID") private String goodsId; diff --git a/framework/src/main/java/cn/lili/modules/member/entity/dto/FootPrintQueryParams.java b/framework/src/main/java/cn/lili/modules/member/entity/dto/FootPrintQueryParams.java new file mode 100644 index 00000000..d2a5ec50 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/member/entity/dto/FootPrintQueryParams.java @@ -0,0 +1,36 @@ +package cn.lili.modules.member.entity.dto; + +import cn.hutool.core.text.CharSequenceUtil; +import cn.lili.common.vo.PageVO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author chc + * @since 2022/6/2114:46 + */ +@Data +@ApiModel +public class FootPrintQueryParams extends PageVO { + + @ApiModelProperty("用户Id") + private String memberId; + + @ApiModelProperty("店铺Id") + private String storeId; + + public QueryWrapper queryWrapper() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (CharSequenceUtil.isNotEmpty(memberId)) { + queryWrapper.eq("member_id", memberId); + } + if (CharSequenceUtil.isNotEmpty(storeId)) { + queryWrapper.eq("store_id", storeId); + } + queryWrapper.eq("delete_flag",false); + queryWrapper.orderByDesc("create_time"); + return queryWrapper; + } +} diff --git a/framework/src/main/java/cn/lili/modules/member/service/FootprintService.java b/framework/src/main/java/cn/lili/modules/member/service/FootprintService.java index 3005ce96..a3ff318e 100644 --- a/framework/src/main/java/cn/lili/modules/member/service/FootprintService.java +++ b/framework/src/main/java/cn/lili/modules/member/service/FootprintService.java @@ -2,6 +2,7 @@ package cn.lili.modules.member.service; import cn.lili.common.vo.PageVO; import cn.lili.modules.member.entity.dos.FootPrint; +import cn.lili.modules.member.entity.dto.FootPrintQueryParams; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; @@ -42,10 +43,10 @@ public interface FootprintService extends IService { /** * 获取会员浏览历史分页 * - * @param pageVO 分页 + * @param params 分页 * @return 会员浏览历史列表 */ - IPage footPrintPage(PageVO pageVO); + IPage footPrintPage(FootPrintQueryParams params); /** * 获取当前会员的浏览记录数量 @@ -53,4 +54,5 @@ public interface FootprintService extends IService { * @return 当前会员的浏览记录数量 */ long getFootprintNum(); + } \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/member/service/MemberService.java b/framework/src/main/java/cn/lili/modules/member/service/MemberService.java index 025c16bc..1b1d8be8 100644 --- a/framework/src/main/java/cn/lili/modules/member/service/MemberService.java +++ b/framework/src/main/java/cn/lili/modules/member/service/MemberService.java @@ -252,7 +252,6 @@ public interface MemberService extends IService { void logout(UserEnums userEnums); /** - * <<<<<<< HEAD * 修改会员是否拥有店铺 * * @param haveStore 是否拥有店铺 diff --git a/framework/src/main/java/cn/lili/modules/member/serviceimpl/FootprintServiceImpl.java b/framework/src/main/java/cn/lili/modules/member/serviceimpl/FootprintServiceImpl.java index cfbbc554..f0c92f6c 100644 --- a/framework/src/main/java/cn/lili/modules/member/serviceimpl/FootprintServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/member/serviceimpl/FootprintServiceImpl.java @@ -3,6 +3,7 @@ package cn.lili.modules.member.serviceimpl; import cn.lili.common.security.context.UserContext; import cn.lili.common.vo.PageVO; import cn.lili.modules.member.entity.dos.FootPrint; +import cn.lili.modules.member.entity.dto.FootPrintQueryParams; import cn.lili.modules.member.mapper.FootprintMapper; import cn.lili.modules.member.service.FootprintService; import cn.lili.modules.search.entity.dos.EsGoodsIndex; @@ -43,19 +44,17 @@ public class FootprintServiceImpl extends ServiceImpl oldPrints = list(queryWrapper); if (oldPrints != null && !oldPrints.isEmpty()) { FootPrint oldPrint = oldPrints.get(0); - oldPrint.setSkuId(footPrint.getSkuId()); - this.updateById(oldPrint); - return oldPrint; - } else { - footPrint.setCreateTime(new Date()); - this.save(footPrint); - //删除超过100条后的记录 - this.baseMapper.deleteLastFootPrint(footPrint.getMemberId()); - return footPrint; + this.removeById(oldPrint.getId()); } + footPrint.setCreateTime(new Date()); + this.save(footPrint); + //删除超过100条后的记录 + this.baseMapper.deleteLastFootPrint(footPrint.getMemberId()); + return footPrint; } @Override @@ -74,15 +73,8 @@ public class FootprintServiceImpl extends ServiceImpl footPrintPage(PageVO pageVO) { - - LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); - lambdaQueryWrapper.eq(FootPrint::getMemberId, UserContext.getCurrentUser().getId()); - lambdaQueryWrapper.eq(FootPrint::getDeleteFlag, false); - lambdaQueryWrapper.orderByDesc(FootPrint::getCreateTime); - IPage footPrintPages = this.page(PageUtil.initPage(pageVO), lambdaQueryWrapper); - - + public IPage footPrintPage(FootPrintQueryParams params) { + IPage footPrintPages = this.page(PageUtil.initPage(params), params.queryWrapper()); //定义结果 IPage esGoodsIndexIPage = new Page<>(); @@ -90,7 +82,7 @@ public class FootprintServiceImpl extends ServiceImpl list = esGoodsSearchService.getEsGoodsBySkuIds( - footPrintPages.getRecords().stream().map(FootPrint::getSkuId).collect(Collectors.toList()), pageVO); + footPrintPages.getRecords().stream().map(FootPrint::getSkuId).collect(Collectors.toList()), params); esGoodsIndexIPage.setPages(footPrintPages.getPages()); esGoodsIndexIPage.setRecords(list); 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..a35c8433 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 @@ -40,13 +40,16 @@ import cn.lili.modules.store.entity.dos.Store; 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.RocketmqSendCallbackBuilder; 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; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; 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.context.ApplicationEventPublisher; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -94,6 +97,9 @@ public class MemberServiceImpl extends ServiceImpl impleme @Autowired private RocketmqCustomProperties rocketmqCustomProperties; + @Autowired + private RocketMQTemplate rocketMQTemplate; + @Autowired private ApplicationEventPublisher applicationEventPublisher; /** @@ -183,7 +189,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); @@ -287,6 +294,8 @@ public class MemberServiceImpl extends ServiceImpl impleme member.setId(SnowFlake.getIdStr()); //保存会员 this.save(member); + + // 发送会员注册信息 applicationEventPublisher.publishEvent(new TransactionCommitSendMQEvent("new member register", rocketmqCustomProperties.getMemberTopic(), MemberTagsEnum.MEMBER_REGISTER.name(), member)); } @@ -299,6 +308,9 @@ public class MemberServiceImpl extends ServiceImpl impleme BeanUtil.copyProperties(memberEditDTO, member); //修改会员 this.updateById(member); + String destination = rocketmqCustomProperties.getMemberTopic() + ":" + MemberTagsEnum.MEMBER_INFO_EDIT.name(); + //发送订单变更mq消息 + rocketMQTemplate.asyncSend(destination, member, RocketmqSendCallbackBuilder.commonCallback()); return member; } 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 d00b1bec..e04782a4 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 @@ -160,35 +160,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/CouponRender.java b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/CouponRender.java index 549dbd04..36d0423a 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/CouponRender.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/CouponRender.java @@ -31,8 +31,6 @@ import java.util.stream.Collectors; @Service public class CouponRender implements CartRenderStep { - @Autowired - private PromotionPriceUtil promotionPriceUtil; @Autowired private MemberCouponService memberCouponService; @@ -267,9 +265,9 @@ public class CouponRender implements CartRenderStep { */ private void renderCouponPrice(Map couponMap, TradeDTO tradeDTO, MemberCoupon coupon, MemberCouponDTO memberCouponDTO) { //分发优惠券 - promotionPriceUtil.recountPrice(tradeDTO, memberCouponDTO.getSkuDetail(), memberCouponDTO.getMemberCoupon().getPrice(), + PromotionPriceUtil.recountPrice(tradeDTO, memberCouponDTO.getSkuDetail(), memberCouponDTO.getMemberCoupon().getPrice(), Boolean.TRUE.equals(coupon.getPlatformFlag()) ? - PromotionTypeEnum.PLATFORM_COUPON : PromotionTypeEnum.COUPON); + PromotionTypeEnum.PLATFORM_COUPON : PromotionTypeEnum.COUPON, memberCouponDTO.getMemberCoupon().getCouponId()); //如果是平台券 则需要计算商家承担比例 if (Boolean.TRUE.equals(coupon.getPlatformFlag()) && coupon.getStoreCommission() > 0) { diff --git a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/FullDiscountRender.java b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/FullDiscountRender.java index dc473902..24618c4b 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/FullDiscountRender.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/FullDiscountRender.java @@ -13,6 +13,7 @@ import cn.lili.modules.order.cart.entity.vo.CartVO; import cn.lili.modules.order.cart.entity.vo.FullDiscountVO; import cn.lili.modules.order.cart.render.CartRenderStep; import cn.lili.modules.order.cart.render.util.PromotionPriceUtil; +import cn.lili.modules.order.order.entity.dto.DiscountPriceItem; import cn.lili.modules.order.order.entity.dto.PriceDetailDTO; import cn.lili.modules.promotion.entity.dos.FullDiscount; import org.springframework.beans.factory.annotation.Autowired; @@ -30,9 +31,6 @@ import java.util.stream.Collectors; @Service public class FullDiscountRender implements CartRenderStep { - @Autowired - private PromotionPriceUtil promotionPriceUtil; - @Autowired private GoodsSkuService goodsSkuService; @@ -84,11 +82,11 @@ public class FullDiscountRender implements CartRenderStep { if (isFull(countPrice, cart)) { //如果减现金 if (Boolean.TRUE.equals(fullDiscount.getFullMinusFlag())) { - promotionPriceUtil.recountPrice(tradeDTO, skuPriceDetail, fullDiscount.getFullMinus(), PromotionTypeEnum.FULL_DISCOUNT); + PromotionPriceUtil.recountPrice(tradeDTO, skuPriceDetail, fullDiscount.getFullMinus(), PromotionTypeEnum.FULL_DISCOUNT, fullDiscountVO.getId()); } //打折 else if (Boolean.TRUE.equals(fullDiscount.getFullRateFlag())) { - this.renderFullRate(cart, skuPriceDetail, CurrencyUtil.div(fullDiscount.getFullRate(), 10)); + this.renderFullRate(cart, skuPriceDetail, CurrencyUtil.div(fullDiscount.getFullRate(), 10), fullDiscountVO.getId()); } //渲染满优惠 renderFullMinus(cart); @@ -107,7 +105,7 @@ public class FullDiscountRender implements CartRenderStep { * @param cart * @param skuPriceDetail */ - private void renderFullRate(CartVO cart, Map skuPriceDetail, Double rate) { + private void renderFullRate(CartVO cart, Map skuPriceDetail, Double rate, String activityId) { List cartSkuVOS = cart.getCheckedSkuList().stream().filter(cartSkuVO -> skuPriceDetail.containsKey(cartSkuVO.getGoodsSku().getId())).collect(Collectors.toList()); @@ -115,14 +113,25 @@ public class FullDiscountRender implements CartRenderStep { cartSkuVOS.forEach(cartSkuVO -> { PriceDetailDTO priceDetailDTO = cartSkuVO.getPriceDetailDTO(); + + Double discountPrice = CurrencyUtil.mul(priceDetailDTO.getGoodsPrice(), + CurrencyUtil.sub(1, rate) + ); //优惠金额=旧的优惠金额+商品金额*商品折扣比例 priceDetailDTO.setDiscountPrice( - CurrencyUtil.add(priceDetailDTO.getDiscountPrice(), - CurrencyUtil.mul(priceDetailDTO.getGoodsPrice(), - CurrencyUtil.sub(1, rate) - ) + CurrencyUtil.add(priceDetailDTO.getDiscountPrice(), discountPrice ) ); + //优惠金额=旧的优惠金额+商品金额*商品折扣比例 + priceDetailDTO.addDiscountPriceItem(DiscountPriceItem + .builder() + .discountPrice(discountPrice) + .promotionTypeEnum(PromotionTypeEnum.FULL_DISCOUNT) + .promotionId(activityId) + .skuId(cartSkuVO.getGoodsSku().getId()) + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + + .build()); }); 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/render/impl/SkuPromotionRender.java b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/SkuPromotionRender.java index 280082ed..b3cb010f 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/render/impl/SkuPromotionRender.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/render/impl/SkuPromotionRender.java @@ -15,6 +15,7 @@ import cn.lili.modules.order.cart.entity.enums.RenderStepEnums; import cn.lili.modules.order.cart.entity.vo.CartSkuVO; import cn.lili.modules.order.cart.entity.vo.CartVO; import cn.lili.modules.order.cart.render.CartRenderStep; +import cn.lili.modules.order.order.entity.dto.DiscountPriceItem; import cn.lili.modules.order.order.entity.dto.PriceDetailDTO; import cn.lili.modules.promotion.entity.dto.search.KanjiaActivitySearchParams; import cn.lili.modules.promotion.entity.enums.KanJiaStatusEnum; @@ -117,6 +118,17 @@ public class SkuPromotionRender implements CartRenderStep { PromotionSkuVO promotionSkuVO = new PromotionSkuVO(PromotionTypeEnum.POINTS_GOODS.name(), cartSkuVO.getPointsId()); cartSkuVO.getPriceDetailDTO().getJoinPromotion().add(promotionSkuVO); totalPayPoints += cartSkuVO.getPoint(); + + //记录优惠由来 + cartSkuVO.getPriceDetailDTO().setDiscountPriceItem( + DiscountPriceItem.builder() + .discountPrice(CurrencyUtil.sub(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getPurchasePrice())) + .promotionId(promotionSkuVO.getActivityId()) + .promotionTypeEnum(PromotionTypeEnum.POINTS_GOODS) + .skuId(cartSkuVO.getGoodsSku().getId()) + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + .build() + ); } } if (userInfo.getPoint() < totalPayPoints) { @@ -138,9 +150,19 @@ public class SkuPromotionRender implements CartRenderStep { cartSkuVO.setSubTotal(kanjiaActivityVO.getPurchasePrice()); cartSkuVO.getPriceDetailDTO().setGoodsPrice(kanjiaActivityVO.getPurchasePrice()); } - PromotionSkuVO promotionSkuVO = new PromotionSkuVO(PromotionTypeEnum.KANJIA.name(), cartSkuVO.getKanjiaId()); cartSkuVO.getPriceDetailDTO().getJoinPromotion().add(promotionSkuVO); + + //记录优惠由来 + cartSkuVO.getPriceDetailDTO().setDiscountPriceItem( + DiscountPriceItem.builder() + .discountPrice(CurrencyUtil.sub(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getPurchasePrice())) + .promotionId(promotionSkuVO.getActivityId()) + .promotionTypeEnum(PromotionTypeEnum.KANJIA) + .skuId(cartSkuVO.getGoodsSku().getId()) + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + .build() + ); } } return; @@ -149,6 +171,17 @@ public class SkuPromotionRender implements CartRenderStep { for (CartSkuVO cartSkuVO : cartVO.getCheckedSkuList()) { PromotionSkuVO promotionSkuVO = new PromotionSkuVO(PromotionTypeEnum.PINTUAN.name(), cartSkuVO.getPintuanId()); cartSkuVO.getPriceDetailDTO().getJoinPromotion().add(promotionSkuVO); + + //记录优惠由来 + cartSkuVO.getPriceDetailDTO().setDiscountPriceItem( + DiscountPriceItem.builder() + .discountPrice(CurrencyUtil.sub(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getPurchasePrice())) + .promotionId(promotionSkuVO.getActivityId()) + .promotionTypeEnum(PromotionTypeEnum.PINTUAN) + .skuId(cartSkuVO.getGoodsSku().getId()) + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + .build() + ); } } return; @@ -171,6 +204,21 @@ public class SkuPromotionRender implements CartRenderStep { cartSkuVO.getPriceDetailDTO().setGoodsPrice(cartSkuVO.getSubTotal()); cartSkuVO.getPriceDetailDTO().getJoinPromotion().add(promotionSkuVO); + + //如果是秒杀活动 + if (promotionSkuVO.getPromotionType().equals(PromotionTypeEnum.SECKILL.name())) { + //需记录秒杀活动详情 + cartSkuVO.getPriceDetailDTO().setDiscountPriceItem( + DiscountPriceItem.builder() + .discountPrice(CurrencyUtil.sub(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getPurchasePrice())) + .promotionId(promotionSkuVO.getActivityId()) + .promotionTypeEnum(PromotionTypeEnum.SECKILL) + .skuId(cartSkuVO.getGoodsSku().getId()) + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + .build()); + } + + } } } diff --git a/framework/src/main/java/cn/lili/modules/order/cart/render/util/PromotionPriceUtil.java b/framework/src/main/java/cn/lili/modules/order/cart/render/util/PromotionPriceUtil.java index b6f1a731..dc1c2348 100644 --- a/framework/src/main/java/cn/lili/modules/order/cart/render/util/PromotionPriceUtil.java +++ b/framework/src/main/java/cn/lili/modules/order/cart/render/util/PromotionPriceUtil.java @@ -4,8 +4,8 @@ import cn.lili.common.enums.PromotionTypeEnum; import cn.lili.common.utils.CurrencyUtil; import cn.lili.modules.order.cart.entity.dto.TradeDTO; import cn.lili.modules.order.cart.entity.vo.CartSkuVO; +import cn.lili.modules.order.order.entity.dto.DiscountPriceItem; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; import java.util.Date; import java.util.List; @@ -17,7 +17,6 @@ import java.util.Map; * @author paulG * @since 2020/8/21 **/ -@Service @Slf4j public class PromotionPriceUtil { @@ -29,7 +28,7 @@ public class PromotionPriceUtil { * @param discountPrice 需要分发的优惠金额 * @param promotionTypeEnum 促销类型 */ - public void recountPrice(TradeDTO tradeDTO, Map skuPromotionDetail, Double discountPrice, PromotionTypeEnum promotionTypeEnum) { + public static void recountPrice(TradeDTO tradeDTO, Map skuPromotionDetail, Double discountPrice, PromotionTypeEnum promotionTypeEnum, String activityId) { // sku 促销信息非空判定 if (skuPromotionDetail == null || skuPromotionDetail.size() == 0) { @@ -102,6 +101,17 @@ public class PromotionPriceUtil { cartSkuVO.getPriceDetailDTO().setCouponPrice( CurrencyUtil.add(cartSkuVO.getPriceDetailDTO().getCouponPrice(), skuDiscountPrice)); + + cartSkuVO.getPriceDetailDTO().addDiscountPriceItem( + DiscountPriceItem.builder() + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + .skuId(cartSkuVO.getGoodsSku().getId()) + .discountPrice(skuDiscountPrice) + .promotionTypeEnum(PromotionTypeEnum.COUPON) + .promotionId(activityId) + .build() + ); + } else if (promotionTypeEnum == PromotionTypeEnum.PLATFORM_COUPON) { cartSkuVO.getPriceDetailDTO().setSiteCouponPrice( @@ -109,9 +119,32 @@ public class PromotionPriceUtil { cartSkuVO.getPriceDetailDTO().setCouponPrice( CurrencyUtil.add(cartSkuVO.getPriceDetailDTO().getCouponPrice(), cartSkuVO.getPriceDetailDTO().getSiteCouponPrice())); + + + cartSkuVO.getPriceDetailDTO().addDiscountPriceItem( + DiscountPriceItem.builder() + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + .skuId(cartSkuVO.getGoodsSku().getId()) + .discountPrice(skuDiscountPrice) + .promotionTypeEnum(PromotionTypeEnum.PLATFORM_COUPON) + .promotionId(activityId) + .build() + ); + } else { cartSkuVO.getPriceDetailDTO().setDiscountPrice( CurrencyUtil.add(cartSkuVO.getPriceDetailDTO().getDiscountPrice(), skuDiscountPrice)); + + //目前剩余的只有满减金额活动。后续如果需要调整,这里建议传递活动类型进来 + cartSkuVO.getPriceDetailDTO().addDiscountPriceItem( + DiscountPriceItem.builder() + .goodsId(cartSkuVO.getGoodsSku().getGoodsId()) + .skuId(cartSkuVO.getGoodsSku().getId()) + .discountPrice(skuDiscountPrice) + .promotionTypeEnum(PromotionTypeEnum.FULL_DISCOUNT) + .promotionId(activityId) + .build() + ); } } } @@ -130,7 +163,7 @@ public class PromotionPriceUtil { * @param promotionId 活动ID * @return 是否有效 */ - private boolean checkPromotionValidTime(Date startTime, Date endTime, String promotionType, String promotionId) { + private static boolean checkPromotionValidTime(Date startTime, Date endTime, String promotionType, String promotionId) { long now = System.currentTimeMillis(); if (startTime.getTime() > now) { log.error("商品ID为{}的{}活动开始时间小于当时时间,活动未开始!", promotionId, promotionType); 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/dto/DiscountPriceItem.java b/framework/src/main/java/cn/lili/modules/order/order/entity/dto/DiscountPriceItem.java new file mode 100644 index 00000000..5391e00f --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/order/order/entity/dto/DiscountPriceItem.java @@ -0,0 +1,44 @@ +package cn.lili.modules.order.order.entity.dto; + +import cn.lili.common.enums.PromotionTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 优惠信息详情 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2022/12/23 14:52 + */ +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DiscountPriceItem { + + + @ApiModelProperty(value = "促销类型") + private PromotionTypeEnum promotionTypeEnum; + + @ApiModelProperty(value = "促销id") + private String promotionId; + + @ApiModelProperty(value = "减免金额") + private Double discountPrice; + + @ApiModelProperty(value = "涉及 商品ID") + private String goodsId; + + @ApiModelProperty(value = "涉及 SKU ID") + private String skuId; + + + public String getPromotionName() { + return promotionTypeEnum.description(); + } +} diff --git a/framework/src/main/java/cn/lili/modules/order/order/entity/dto/PriceDetailDTO.java b/framework/src/main/java/cn/lili/modules/order/order/entity/dto/PriceDetailDTO.java index edf3cfc9..76f6dad6 100644 --- a/framework/src/main/java/cn/lili/modules/order/order/entity/dto/PriceDetailDTO.java +++ b/framework/src/main/java/cn/lili/modules/order/order/entity/dto/PriceDetailDTO.java @@ -42,6 +42,9 @@ public class PriceDetailDTO implements Serializable { @ApiModelProperty(value = "优惠金额") private Double discountPrice; + @ApiModelProperty(value = "优惠详情") + private List discountPriceDetail; + @ApiModelProperty(value = "优惠券金额") private Double couponPrice; @@ -101,6 +104,27 @@ public class PriceDetailDTO implements Serializable { private List joinPromotion; + /** + * 设置促销详情 + * + * @param discountPriceItem 促销信息 + */ + public void setDiscountPriceItem(DiscountPriceItem discountPriceItem) { + List discountPriceItems = new ArrayList<>(); + discountPriceItems.add(discountPriceItem); + this.discountPriceDetail = discountPriceItems; + } + + /** + * 设置促销详情 + * + * @param discountPriceItem 促销信息 + */ + public void addDiscountPriceItem(DiscountPriceItem discountPriceItem) { + discountPriceDetail.add(discountPriceItem); + } + + public Double getOriginalPrice() { if (originalPrice == 0D) { return flowPrice; @@ -134,6 +158,7 @@ public class PriceDetailDTO implements Serializable { billPrice = 0d; settlementPrice = 0d; + discountPriceDetail = new ArrayList<>(); joinPromotion = new ArrayList<>(); } @@ -204,6 +229,8 @@ public class PriceDetailDTO implements Serializable { billPrice = CurrencyUtil.add(billPrice, priceDetailDTO.getBillPrice()); settlementPrice = CurrencyUtil.add(settlementPrice, priceDetailDTO.getSettlementPrice()); + discountPriceDetail.addAll(priceDetailDTO.getDiscountPriceDetail()); + } /** 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/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