Merge branch 'master' of gitee.com:beijing_hongye_huicheng/lilishop into feature/pg

This commit is contained in:
paulGao 2023-01-10 14:34:52 +08:00
commit 5080cf65c7
139 changed files with 4832 additions and 345 deletions

View File

@ -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 '默认页面是否开启';

View File

@ -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';

View File

@ -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<IPage<EsGoodsIndex>> getByPage(PageVO page) {
return ResultUtil.data(footprintService.footPrintPage(page));
public ResultMessage<IPage<EsGoodsIndex>> getByPage(FootPrintQueryParams params) {
params.setMemberId(UserContext.getCurrentUser().getId());
return ResultUtil.data(footprintService.footPrintPage(params));
}
@ApiOperation(value = "根据id删除")

View File

@ -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<Object> 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<Object> 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<Object> 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"),

View File

@ -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<List<MemberCoupon>> 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<IPage<CouponVO>> getCouponList(CouponSearchParams queryParam, PageVO page) {

View File

@ -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<IPage<StoreAddress>> 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<StoreAddress> get(@PathVariable String id) {
StoreAddress address = OperationalJudgment.judgment(storeAddressService.getById(id));
return ResultUtil.data(address);
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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());

View File

@ -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<ImTalk> imTalkList1 = imTalkService.list(new LambdaQueryWrapper<ImTalk>().eq(ImTalk::getUserId1, member.getId()));
for (ImTalk imTalk : imTalkList1) {
imTalk.setName1(member.getNickName());
imTalk.setFace1(member.getFace());
}
imTalkService.updateBatchById(imTalkList1);
List<ImTalk> imTalkList2 = imTalkService.list(new LambdaQueryWrapper<ImTalk>().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<ImTalk> imTalkList1 = imTalkService.list(new LambdaQueryWrapper<ImTalk>().eq(ImTalk::getUserId1, store.getId()));
for (ImTalk imTalk : imTalkList1) {
imTalk.setName1(store.getStoreName());
imTalk.setFace1(store.getStoreLogo());
}
imTalkService.updateBatchById(imTalkList1);
List<ImTalk> imTalkList2 = imTalkService.list(new LambdaQueryWrapper<ImTalk>().eq(ImTalk::getUserId2, store.getId()));
for (ImTalk imTalk : imTalkList2) {
imTalk.setName2(store.getStoreName());
imTalk.setFace2(store.getStoreLogo());
}
imTalkService.updateBatchById(imTalkList2);
}
}

View File

@ -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<CouponActivity> couponActivities = couponActivityService.list(new QueryWrapper<CouponActivity>()
.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());
}
}
}

View File

@ -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());
//获取随机数判定是否存在

View File

@ -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());

View File

@ -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<MessageExt> {
@Autowired
private List<MemberLoginEvent> memberLoginEvents;
@Autowired
private List<MemberInfoChangeEvent> memberInfoChangeEvents;
@Override
public void onMessage(MessageExt messageExt) {
@ -110,6 +111,20 @@ public class MemberMessageListener implements RocketMQListener<MessageExt> {
}
}
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) {

View File

@ -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<MessageExt> {
@Autowired
private List<StoreSettingChangeEvent> 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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -51,7 +51,10 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

View File

@ -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) {

View File

@ -185,7 +185,7 @@ public class RedisCache implements Cache {
public Long counter(Object key) {
HyperLogLogOperations<Object, Object> operations = redisTemplate.opsForHyperLogLog();
//add 方法对应 PFADD 命令
//add 方法对应 PFCOUNT 命令
return operations.size(key);
}

View File

@ -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"),
/**
* 其他促销

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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;

View File

@ -14,7 +14,8 @@ public enum UserEnums {
MEMBER("会员"),
STORE("商家"),
MANAGER("管理员"),
SYSTEM("系统");
SYSTEM("系统"),
SEAT("坐席");
private final String role;
UserEnums(String role) {

View File

@ -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() {

View File

@ -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;
}
/**
* 获取延时时间
*

View File

@ -246,7 +246,17 @@ public class ConnectServiceImpl extends ServiceImpl<ConnectMapper, Connect> 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);

View File

@ -241,12 +241,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> i
}
}
UpdateWrapper<Category> 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();
}

View File

@ -327,7 +327,7 @@ public class GoodsSkuServiceImpl extends ServiceImpl<GoodsSkuMapper, GoodsSku> 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());
}

View File

@ -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> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
return context.getBean(clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
CustomSpringConfigurator.context = applicationContext;
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <T> QueryWrapper<T> queryWrapper() {
QueryWrapper<T> 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;
}
}

View File

@ -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<ImMessage> initQueryWrapper() {
if (StringUtils.isEmpty(talkId)) {
throw new ServiceException(ResultCode.ERROR);
}
if (num == null || num > 50) {
num = 50;
}
LambdaQueryWrapper<ImMessage> 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;
}
}

View File

@ -0,0 +1,28 @@
package cn.lili.modules.im.entity.enums;
/**
* 返回消息类型枚举
*
* @author liushuai
*/
public enum MessageResultType {
/**
* 返回消息类型枚举
* <p>
* 好友列表
* 增加好友
* 消息
* 阅读消息
* 未读消息
* 历史消息
* 系统提示
*/
FRIENDS,
ADD_FRIENDS,
MESSAGE,
READ_MESSAGE,
UN_READ,
HISTORY,
SYSTEM_TIPS
}

View File

@ -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;
}

View File

@ -0,0 +1,23 @@
package cn.lili.modules.im.entity.enums;
/**
* 消息类型
*
* @author liushuai
*/
public enum MessageTypeEnum {
/**
* 消息类型枚举
* <p>
* 普通消息
* 图片
* 语音
* 视频
*/
MESSAGE,
PICTURE,
VOICE,
GOODS,
ORDER,
VIDEO
}

View File

@ -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;
}

View File

@ -0,0 +1,26 @@
package cn.lili.modules.im.entity.enums;
/**
* 操作类型枚举
*
* @author liushuai
*/
public enum OperationType {
/**
* 消息类型枚举
* <p>
* 心跳检测
* 发起聊天
* 发起消息
* 查询历史消息
* 阅读消息
* 查询未读消息
*/
PING,
CREATE,
MESSAGE,
HISTORY,
READ,
UNREAD,
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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<String> readMessageList;
}

View File

@ -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;
}

View File

@ -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<ImMessage> {
}

View File

@ -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<ImTalk> {
}

View File

@ -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<QA> {
}

View File

@ -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<Seat> {
}

View File

@ -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<SeatSetting> {
}

View File

@ -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<ImMessage> {
/**
* 阅读消息
*
* @param talkId
* @param accessToken
*/
void read(String talkId, String accessToken);
/**
* 未读消息列表
*
* @param accessToken
*/
List<ImMessage> unReadMessages(String accessToken);
/**
* 历史消息
*
* @param accessToken
* @param to
*/
List<ImMessage> historyMessage(String accessToken, String to);
/**
* 是否有新消息
* @param accessToken
* @return
*/
Boolean hasNewMessage(String accessToken);
/**
* 分页获取消息列表
* @param messageQueryParams 查询条件
* @return 消息列表
*/
List<ImMessage> getList(MessageQueryParams messageQueryParams);
/**
* 获取所有未读消息
* @return
*/
Long unreadMessageCount();
/**
* 清空所有未读消息
*/
void cleanUnreadMessage();
}

View File

@ -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<ImTalk> {
/**
* 获取与某人的聊天框
*
* @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<ImTalkVO> getUserTalkList(String userName);
/**
* 获取商家聊天列表
* @return
*/
List<ImTalkVO> getStoreTalkList();
}

View File

@ -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<QA> {
/**
* 查询店铺问题
* @param word
* @param pageVO
* @return
*/
IPage<QA> getStoreQA(String word, PageVO pageVO);
}

View File

@ -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<Seat> {
/**
* 获取坐席列表
*
* @param storeId 店铺id
* @return
*/
List<SeatVO> 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);
}

View File

@ -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<SeatSetting> {
/**
* 根据店铺id获取坐席配置
*
* @param storeId
* @return
*/
SeatSetting getSetting(String storeId);
/**
* 根据店铺修改坐席设置
*
* @param seatSetting 坐席设置
* @return
*/
SeatSetting updateByStore(SeatSetting seatSetting);
}

View File

@ -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<ImMessageMapper, ImMessage> implements ImMessageService {
@Autowired
private ImTalkService imTalkService;
@Override
public void read(String talkId, String accessToken) {
LambdaUpdateWrapper<ImMessage> 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<ImMessage> unReadMessages(String accessToken) {
String userId = UserContext.getAuthUser(accessToken).getId();
LambdaQueryWrapper<ImMessage> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImMessage::getToUser, userId);
queryWrapper.eq(ImMessage::getIsRead, false);
return this.list(queryWrapper);
}
@Override
public List<ImMessage> historyMessage(String accessToken, String to) {
String userId = UserContext.getAuthUser(accessToken).getId();
LambdaQueryWrapper<ImMessage> 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<ImMessage> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ImMessage::getIsRead, false);
queryWrapper.eq(ImMessage::getToUser, userId);
return this.list(queryWrapper).size() > 0;
}
@Override
public List<ImMessage> getList(MessageQueryParams messageQueryParams) {
List<ImMessage> 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<ImMessage>().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<ImMessage>().eq(ImMessage::getToUser,currentUser.getId()).set(ImMessage::getIsRead,true));
}
/**
* 根据时间倒叙
*
* @param list
*/
private static void ListSort(List<ImMessage> list) {
list.sort(new Comparator<ImMessage>() {
@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<ImMessage> messageList) {
if (messageList.size() > 0) {
for (ImMessage imMessage : messageList) {
if(Boolean.FALSE.equals(imMessage.getIsRead())){
imMessage.setIsRead(true);
}
}
}
this.updateBatchById(messageList);
}
}

View File

@ -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<ImTalkMapper, ImTalk> implements ImTalkService {
@Autowired
private MemberService memberService;
@Autowired
private StoreService storeService;
@Autowired
private ImMessageService imMessageService;
@Override
public ImTalk getTalkByUser(String userId1, String userId2) {
LambdaQueryWrapper<ImTalk> 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<ImTalkVO> getUserTalkList(String userName) {
AuthUser authUser = UserContext.getCurrentUser();
if(authUser == null){
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
LambdaQueryWrapper<ImTalk> 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<ImTalk> imTalks = this.list(queryWrapper);
List<ImTalkVO> imTalkVOList = imTalks.stream().map(imTalk -> {
return new ImTalkVO(imTalk, authUser.getId());
}).collect(Collectors.toList());
getUnread(imTalkVOList);
return imTalkVOList;
}
@Override
public List<ImTalkVO> getStoreTalkList() {
AuthUser authUser = UserContext.getCurrentUser();
if(authUser == null){
throw new ServiceException(ResultCode.STORE_NOT_LOGIN_ERROR);
}
LambdaQueryWrapper<ImTalk> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.and(wq->{
wq.like(ImTalk::getUserId1, authUser.getStoreId()).or().like(ImTalk::getUserId2,authUser.getStoreId());
});
queryWrapper.orderByDesc(ImTalk::getLastTalkTime);
List<ImTalk> imTalks = this.list(queryWrapper);
List<ImTalkVO> imTalkVOList = imTalks.stream().map(imTalk -> {
return new ImTalkVO(imTalk, authUser.getStoreId());
}).collect(Collectors.toList());
getUnread(imTalkVOList);
return imTalkVOList;
}
/**
* 获取未读消息数量
* @param imTalkVOList
*/
private void getUnread(List<ImTalkVO> imTalkVOList){
if(imTalkVOList.size() > 0){
for (ImTalkVO imTalkVO : imTalkVOList) {
long count = imMessageService.count(new LambdaQueryWrapper<ImMessage>().eq(ImMessage::getFromUser, imTalkVO.getUserId()).eq(ImMessage::getIsRead, false));
imTalkVO.setUnread(count);
}
}
}
}

View File

@ -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<QAMapper, QA> implements QAService {
@Override
public IPage<QA> getStoreQA(String word, PageVO pageVo) {
LambdaQueryWrapper<QA> qaLambdaQueryWrapper = new LambdaQueryWrapper<>();
qaLambdaQueryWrapper.eq(QA::getTenantId, UserContext.getCurrentUser().getTenantId());
qaLambdaQueryWrapper.like(QA::getQuestion, word);
return this.page(PageUtil.initPage(pageVo), qaLambdaQueryWrapper);
}
}

View File

@ -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<SeatMapper, Seat> implements SeatService {
@Autowired
private SeatTokenGenerate seatTokenGenerate;
@Autowired
private Cache<String> cache;
/**
* 快捷登录缓存前缀
*/
private static String prefix = "{quick_login}_";
@Override
public List<SeatVO> seatVoList(String storeId) {
LambdaQueryWrapper<Seat> seatLambdaQueryWrapper = new LambdaQueryWrapper<>();
seatLambdaQueryWrapper.eq(Seat::getTenantId, storeId);
List<Seat> list = this.list(seatLambdaQueryWrapper);
//转换模型为VO
List<SeatVO> 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<Seat> seatLambdaQueryWrapper = new LambdaQueryWrapper<>();
seatLambdaQueryWrapper.eq(Seat::getUsername, username);
return this.getOne(seatLambdaQueryWrapper);
}
}

View File

@ -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<SeatSettingMapper, SeatSetting> implements SeatSettingService {
@Override
public SeatSetting getSetting(String storeId) {
LambdaQueryWrapper<SeatSetting> 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;
}
}

View File

@ -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<Seat> {
@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);
}
}

View File

@ -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");
}

View File

@ -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;

View File

@ -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 <T> QueryWrapper<T> queryWrapper() {
QueryWrapper<T> 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;
}
}

View File

@ -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<FootPrint> {
/**
* 获取会员浏览历史分页
*
* @param pageVO 分页
* @param params 分页
* @return 会员浏览历史列表
*/
IPage<EsGoodsIndex> footPrintPage(PageVO pageVO);
IPage<EsGoodsIndex> footPrintPage(FootPrintQueryParams params);
/**
* 获取当前会员的浏览记录数量
@ -53,4 +54,5 @@ public interface FootprintService extends IService<FootPrint> {
* @return 当前会员的浏览记录数量
*/
long getFootprintNum();
}

View File

@ -252,7 +252,6 @@ public interface MemberService extends IService<Member> {
void logout(UserEnums userEnums);
/**
* <<<<<<< HEAD
* 修改会员是否拥有店铺
*
* @param haveStore 是否拥有店铺

View File

@ -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,20 +44,18 @@ public class FootprintServiceImpl extends ServiceImpl<FootprintMapper, FootPrint
queryWrapper.eq(FootPrint::getGoodsId, footPrint.getGoodsId());
//如果已存在某商品记录则更新其修改时间
//如果不存在则添加记录
//为了保证足迹的排序,将原本足迹删除后重新添加
List<FootPrint> oldPrints = list(queryWrapper);
if (oldPrints != null && !oldPrints.isEmpty()) {
FootPrint oldPrint = oldPrints.get(0);
oldPrint.setSkuId(footPrint.getSkuId());
this.updateById(oldPrint);
return oldPrint;
} else {
this.removeById(oldPrint.getId());
}
footPrint.setCreateTime(new Date());
this.save(footPrint);
//删除超过100条后的记录
this.baseMapper.deleteLastFootPrint(footPrint.getMemberId());
return footPrint;
}
}
@Override
public boolean clean() {
@ -74,15 +73,8 @@ public class FootprintServiceImpl extends ServiceImpl<FootprintMapper, FootPrint
}
@Override
public IPage<EsGoodsIndex> footPrintPage(PageVO pageVO) {
LambdaQueryWrapper<FootPrint> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(FootPrint::getMemberId, UserContext.getCurrentUser().getId());
lambdaQueryWrapper.eq(FootPrint::getDeleteFlag, false);
lambdaQueryWrapper.orderByDesc(FootPrint::getCreateTime);
IPage<FootPrint> footPrintPages = this.page(PageUtil.initPage(pageVO), lambdaQueryWrapper);
public IPage<EsGoodsIndex> footPrintPage(FootPrintQueryParams params) {
IPage<FootPrint> footPrintPages = this.page(PageUtil.initPage(params), params.queryWrapper());
//定义结果
IPage<EsGoodsIndex> esGoodsIndexIPage = new Page<>();
@ -90,7 +82,7 @@ public class FootprintServiceImpl extends ServiceImpl<FootprintMapper, FootPrint
return esGoodsIndexIPage;
} else {
List<EsGoodsIndex> 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);

View File

@ -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<MemberMapper, Member> impleme
@Autowired
private RocketmqCustomProperties rocketmqCustomProperties;
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
/**
@ -183,7 +189,8 @@ public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> 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<Member>().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<MemberMapper, Member> 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<MemberMapper, Member> 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;
}

View File

@ -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;
/**
* 客户端类型

View File

@ -160,7 +160,7 @@ public class CheckDataRender implements CartRenderStep {
private void groupStore(TradeDTO tradeDTO) {
//渲染的购物车
List<CartVO> cartList = new ArrayList<>();
if(tradeDTO.getCartList() == null || tradeDTO.getCartList().size() == 0){
//根据店铺分组
Map<String, List<CartSkuVO>> storeCollect = tradeDTO.getSkuList().stream().collect(Collectors.groupingBy(CartSkuVO::getStoreId));
for (Map.Entry<String, List<CartSkuVO>> storeCart : storeCollect.entrySet()) {
@ -191,6 +191,8 @@ public class CheckDataRender implements CartRenderStep {
tradeDTO.setCartList(cartList);
}
}
/**
* 订单预校验
* 1自己拼团自己创建都拼团判定拼团限购

View File

@ -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<String, Double> 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) {

View File

@ -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<String, Double> skuPriceDetail, Double rate) {
private void renderFullRate(CartVO cart, Map<String, Double> skuPriceDetail, Double rate, String activityId) {
List<CartSkuVO> 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());
});

View File

@ -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,10 +44,14 @@ public class SkuFreightRender implements CartRenderStep {
List<CartSkuVO> cartSkuVOS = tradeDTO.getCheckedSkuList();
//会员收货地址问题处理
MemberAddress memberAddress = tradeDTO.getMemberAddress();
StoreAddress storeAddress = tradeDTO.getStoreAddress();
//如果收货地址为空则抛出异常
if (memberAddress == null) {
if (memberAddress == null && storeAddress == null) {
return;
}
//选择物流的时候计算价格
if(DeliveryMethodEnum.LOGISTICS.name().equals(tradeDTO.getCartList().get(0).getDeliveryMethod())){
if (memberAddress != null) {
//运费分组信息
Map<String, List<String>> freightGroups = freightTemplateGrouping(cartSkuVOS);
@ -110,6 +116,8 @@ public class SkuFreightRender implements CartRenderStep {
}
}
}
}
}
/**

View File

@ -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());
}
}
}
}

View File

@ -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<String, Double> skuPromotionDetail, Double discountPrice, PromotionTypeEnum promotionTypeEnum) {
public static void recountPrice(TradeDTO tradeDTO, Map<String, Double> 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);

View File

@ -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<String> shippingMethodList(String way);
}

View File

@ -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());
}
}
this.resetTradeDTO(tradeDTO);
TradeDTO neTradeDTO = (TradeDTO) cache.get(this.getOriginKey(cartTypeEnum));
}
/**
@ -547,15 +569,33 @@ public class CartServiceImpl implements CartService {
tradeDTO.setStoreRemark(tradeParams.getRemark());
tradeDTO.setParentOrderSn(tradeParams.getParentOrderSn());
//订单无收货地址校验
if(tradeDTO.getStoreAddress() == null){
if (tradeDTO.getMemberAddress() == null) {
throw new ServiceException(ResultCode.MEMBER_ADDRESS_NOT_EXIST);
}
}
//构建交易
Trade trade = tradeBuilder.createTrade(tradeDTO);
this.cleanChecked(this.readDTO(cartTypeEnum));
return trade;
}
@Override
public List<String> shippingMethodList(String way) {
List<String> list = new ArrayList<String>();
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;
}
/**
* 获取购物车类型

View File

@ -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());
//会员收件信息
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());

View File

@ -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();
}
}

View File

@ -42,6 +42,9 @@ public class PriceDetailDTO implements Serializable {
@ApiModelProperty(value = "优惠金额")
private Double discountPrice;
@ApiModelProperty(value = "优惠详情")
private List<DiscountPriceItem> discountPriceDetail;
@ApiModelProperty(value = "优惠券金额")
private Double couponPrice;
@ -101,6 +104,27 @@ public class PriceDetailDTO implements Serializable {
private List<PromotionSkuVO> joinPromotion;
/**
* 设置促销详情
*
* @param discountPriceItem 促销信息
*/
public void setDiscountPriceItem(DiscountPriceItem discountPriceItem) {
List<DiscountPriceItem> 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());
}
/**

View File

@ -16,6 +16,7 @@ public enum OrderStatusEnum {
UNDELIVERED("待发货"),
DELIVERED("已发货"),
COMPLETED("已完成"),
STAY_PICKED_UP("待自提"),
/**
* 虚拟订单需要核验商品
*/

View File

@ -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;
}
//新订单允许支付

View File

@ -183,6 +183,15 @@ public interface OrderService extends IService<Order> {
*/
Order take(String orderSn, String verificationCode);
/**
* 订单核验
*
* @param verificationCode 验证码
* @return 订单
*/
Order take(String verificationCode);
/**
* 根据核验码获取订单信息
*

View File

@ -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<OrderMapper, Order> 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<OrderMapper, Order> implements
return order;
}
@Override
public Order take(String verificationCode) {
String storeId = OperationalJudgment.judgment(UserContext.getCurrentUser()).getStoreId();
Order order = this.getOne(new LambdaQueryWrapper<Order>().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<Order>()
.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<OrderMapper, Order> 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<Order>()
.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);
}

File diff suppressed because one or more lines are too long

View File

@ -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<AdminUser> {
*/
Token refreshToken(String refreshToken);
/**
* 登出
*
* @param userEnums token角色类型
*/
void logout(UserEnums userEnums);
}

View File

@ -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<AdminUserMapper, AdminUser
private MenuService menuService;
@Autowired
private ManagerTokenGenerate managerTokenGenerate;
@Autowired
private Cache cache;
/**
* 角色长度
*/
@ -132,6 +139,14 @@ public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser
return managerTokenGenerate.refreshToken(refreshToken);
}
@Override
public void logout(UserEnums userEnums) {
String currentUserToken = UserContext.getCurrentUserToken();
if (CharSequenceUtil.isNotEmpty(currentUserToken)) {
cache.remove(CachePrefix.ACCESS_TOKEN.getPrefix(userEnums) + currentUserToken);
}
}
@Override
public AdminUser findByUsername(String username) {

View File

@ -2,6 +2,7 @@ package cn.lili.modules.promotion.entity.dos;
import cn.lili.modules.promotion.entity.enums.CouponActivitySendTypeEnum;
import cn.lili.modules.promotion.entity.enums.CouponActivityTypeEnum;
import cn.lili.modules.promotion.entity.enums.CouponFrequencyEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -26,15 +27,22 @@ public class CouponActivity extends BasePromotions {
* @see CouponActivityTypeEnum
*/
@NotNull(message = "优惠券活动类型不能为空")
@ApiModelProperty(value = "优惠券活动类型", allowableValues = "REGISTERED:新人赠券,SPECIFY精确发券")
@ApiModelProperty(value = "优惠券活动类型", allowableValues = "REGISTERED:新人赠券,INVITE_NEW邀新赠券AUTO_COUPON自动赠券SPECIFY精确发券")
private String couponActivityType;
/**
* @see CouponActivitySendTypeEnum
*/
//目前仅在自动赠券模式下该参数会生效日后如果完善发送测略则调整这里即可
@NotNull(message = "请选择活动范围")
@ApiModelProperty(value = "活动范围", allowableValues = "ALL:全部会员,DESIGNATED指定会员")
private String activityScope;
/**
* @see CouponFrequencyEnum
*/
@NotNull(message = "领取周期")
@ApiModelProperty(value = "活动范围", allowableValues = " DAY:每天, WEEK:每周, MONTH:每月")
private String couponFrequencyEnum;
@ApiModelProperty(value = "活动范围详情,只有精准发券使用")
private String activityScopeInfo;

View File

@ -0,0 +1,50 @@
package cn.lili.modules.promotion.entity.dos;
import cn.lili.mybatis.BaseIdEntity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* 会员优惠券实体类
*
* @author Chopper
* @since 2020-03-19 10:44 上午
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("li_member_coupon_sign")
@ApiModel(value = "会员优惠券领取标记")
public class MemberCouponSign extends BaseIdEntity {
@ApiModelProperty(value = "优惠券活动ID")
private String couponActivityId;
@ApiModelProperty(value = "会员ID")
private String memberId;
@ApiModelProperty(value = "失效时间,到达失效时间后自动删除,用户可以再次领取")
private Date invalidTime;
@CreatedDate
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(value = "创建时间", hidden = true)
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd || yyyy/MM/dd HH:mm:ss|| yyyy/MM/dd ||epoch_millis")
private Date createTime;
}

View File

@ -0,0 +1,32 @@
package cn.lili.modules.promotion.entity.dto;
import cn.lili.modules.promotion.entity.enums.CouponActivityTypeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 优惠券活动触发
*
* @author paulG
* @since 2020/10/9
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CouponActivityTrigger {
@ApiModelProperty(value = "用户ID")
private String userId;
@ApiModelProperty(value = "用户昵称")
private String nickName;
@ApiModelProperty(value = "优惠券活动类型")
private CouponActivityTypeEnum couponActivityTypeEnum;
}

View File

@ -13,7 +13,15 @@ public enum CouponActivityTypeEnum {
*/
REGISTERED("新人赠券"),
/**
* "精确发券"
* "邀新赠券"
*/
INVITE_NEW("邀新赠券"),
/**
* "自动赠券"
*/
AUTO_COUPON("自动赠券"),
/**
* "定向发券"
*/
SPECIFY("精确发券");

View File

@ -0,0 +1,35 @@
package cn.lili.modules.promotion.entity.enums;
/**
* 优惠券活动发送类型枚举
*
* @author Bulbasaur
* @since 2021/5/20 5:47 下午
*/
public enum CouponFrequencyEnum {
/**
* 领取周期
*/
DAY("每天"), WEEK("每周"), MONTH("每月");
private final String description;
CouponFrequencyEnum(String str) {
this.description = str;
}
public String description() {
return description;
}
public static boolean exist(String name) {
try {
CouponFrequencyEnum.valueOf(name);
} catch (IllegalArgumentException e) {
return false;
}
return true;
}
}

View File

@ -23,5 +23,14 @@ public enum CouponRangeDayEnum {
return description;
}
public static boolean exist(String name) {
try {
CouponRangeDayEnum.valueOf(name);
} catch (IllegalArgumentException e) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,17 @@
package cn.lili.modules.promotion.mapper;
import cn.lili.modules.promotion.entity.dos.MemberCouponSign;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 会员优惠券领取标记
*
* @author liushuai(liushuai711 @ gmail.com)
* @version v4.0
* @Description:
* @since 2023/1/3 18:11
*/
public interface MemberCouponSignMapper extends BaseMapper<MemberCouponSign> {
}

View File

@ -1,7 +1,8 @@
package cn.lili.modules.promotion.service;
import cn.lili.modules.member.entity.dos.Member;
import cn.lili.modules.promotion.entity.dos.CouponActivity;
import cn.lili.modules.promotion.entity.dos.MemberCoupon;
import cn.lili.modules.promotion.entity.dto.CouponActivityTrigger;
import cn.lili.modules.promotion.entity.vos.CouponActivityVO;
import java.util.List;
@ -27,16 +28,15 @@ public interface CouponActivityService extends AbstractPromotionsService<CouponA
/**
* 精准发券
*
* @param couponActivityId 优惠券活动ID
* @param couponActivity 精准发券
*/
void specify(String couponActivityId);
void specify(CouponActivity couponActivity);
/**
* 注册赠券
* 用户优惠券活动触发
*
* @param couponActivityList 优惠券活动
* @param member 会员
* @return 优惠券列表
*/
void registered(List<CouponActivity> couponActivityList, Member member);
List<MemberCoupon> trigger(CouponActivityTrigger couponActivityTrigger);
}

Some files were not shown because too many files have changed in this diff Show More