package com.cyksj.service.user.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.cyksj.common.constant.Constant; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.task.GlobalThreadPoolTaskExecutor; import com.cyksj.common.util.Codec; import com.cyksj.common.util.Jsons; import com.cyksj.common.util.StringUtil; import com.cyksj.config.wxlogin.WxOpenPlatYHLXLoginConfig; import com.cyksj.mapper.PhoneCodeMapper; import com.cyksj.mapper.UserMapper; import com.cyksj.mapper.channel.ChannelPopularizeMapper; import com.cyksj.mapper.manage.cps.UserDistributePopularizeMapper; import com.cyksj.mapper.market.task.UserBindDetailMapper; import com.cyksj.model.dto.*; import com.cyksj.model.entity.*; import com.cyksj.model.request.LoginReq; import com.cyksj.redis.RedisService; import com.cyksj.service.distribute.DistributeService; import com.cyksj.service.distribute.equipment.EquipmentDistributeService; import com.cyksj.service.mange.coupon.CouponCommonService; import com.cyksj.service.market.task.BindTaskService; import com.cyksj.service.sys.SysConfigService; import com.cyksj.service.user.UserService; import com.cyksj.service.wechat.WeChatService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Optional; /** * @author chan * @date 2021/10/10 下午3:27 */ @Slf4j @Service @RequiredArgsConstructor public class UserServiceImpl extends ServiceImpl implements UserService { private final DistributeService distributeService; private final EquipmentDistributeService equipDistributeService; private final ChannelPopularizeMapper channelPopularizeMapper; private final CouponCommonService couponCommonService; private final RedisService redisService; private final SysConfigService sysConfigService; private final UserBindDetailMapper userBindDetailMapper; private final UserDistributePopularizeMapper distributePopularizeMapper; private final UserMapper userMapper; private final PhoneCodeMapper phoneCodeMapper; private final WeChatService weChatService; private final BindTaskService bindTaskService; private final WxOpenPlatYHLXLoginConfig wxOpenPlatYHLXLoginConfig; private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance(); @Override public User saveAuth(GzhOAuth2UserInfo info, Long sharedId, Integer dsType, Long pid, User.RegisterEnv registerEnv, String dsCode, String callback, String callbackType) throws Exception { final String unionid = info.getUnionid(); if (StrUtil.isEmpty(unionid)) { throw BusinessRuntimeException.getInstance("授权操作异常,请刷新页面"); } User user = getSyncUser(info.getOpenid(), info.getUnionid(), null); user = Optional.ofNullable(user).orElseGet(() -> new User() .setUnionid(unionid)); user.setCountry(info.getCountry()) .setProvince(info.getProvince()) .setCity(info.getCity()); if (user.getSex() == null) { user.setSex(info.getSex()); } if (StrUtil.isEmpty(user.getHeadimgurl())) { user.setHeadimgurl(info.getHeadimgurl()); } if (StrUtil.isEmpty(user.getNickname())) { user.setNickname(info.getNickname()); } user.setUnionid(unionid); user.setOpenId(info.getOpenid()); Boolean isNewUser = false; if (user.getId() == null) { isNewUser = true; user.setPopularizeId(pid); user.setRegisterEnv(registerEnv.name()); if (!redisService.setNx(RedisService.key.REPEAT_USER_KEY.getNameFormat(user.getUnionid()), user.getUnionid(), RedisService.key.REPEAT_USER_KEY.getTimeout())) { return this.getOne(Wrappers.lambdaQuery(User.class) .eq(User::getUnionid, unionid).last("limit 1")); } this.save(user); //缓存用户注册 回传信息 if (StrUtil.isNotBlank(callback)) { OrderDonPostDataDto orderDonPostDataDto = new OrderDonPostDataDto().setCallback(callback) .setCallbackType(callbackType); redisService.set(RedisService.key.ORDER_DON_POST_DATA_USER_KEY.getName() + user.getId(), Jsons.toJson(orderDonPostDataDto)); } //发放新用户福利 final Long fUid = user.getId(); TASK_POOL.execute(() -> { try { sendNewUserWelfare(fUid); } catch (Exception e) { } }); } else { if (StrUtil.isEmpty(user.getRegisterEnv())) { user.setRegisterEnv(registerEnv.name()); } this.updateById(user); } Long dsPopularizeId = null; if (StrUtil.isNotBlank(dsCode)) { dsCode = dsCode.trim(); User sharedUser = getOne(Wrappers.lambdaQuery(User.class) .eq(User::getShowId, dsCode).last("limit 1")); if (sharedUser != null) { sharedId = sharedUser.getId(); } else { UserDistributePopularize distributePopularize = distributePopularizeMapper.selectOne(Wrappers.lambdaQuery(UserDistributePopularize.class) .eq(UserDistributePopularize::getCode, dsCode) .select(UserDistributePopularize::getUserId, UserDistributePopularize::getId).last("limit 1")); if (distributePopularize != null) { log.info("渠道sharedId:{}设置固定推广链接用户分销", distributePopularize.getUserId()); sharedId = distributePopularize.getUserId(); dsPopularizeId = distributePopularize.getId(); } } } if (sharedId != null && isNewUser) { if (dsType == null || dsType == 1) { distributeService.saveDistributionInvitation(sharedId, user.getId(), dsPopularizeId); } } Long userId = user.getId(); if (isNewUser && pid != null) { TASK_POOL.execute(() -> { sendFixedCustomerCoupon(pid, userId, unionid); }); } //新旧用户都可实物分销 if (sharedId != null && dsType != null && dsType == 2) { equipDistributeService.saveDistributionInvitation(sharedId, isNewUser, user.getId()); } return user; } @Override public UserWhoami whoami(long userId) { User user = this.getById(userId); Assert.notNull(user, "业务处理失败,请联系客服"); UserWhoami userWhoami = new UserWhoami(); if (StrUtil.isEmpty(user.getShowId())) { user.setShowId(getUserShowId(userId)); } BeanUtil.copyProperties(user, userWhoami); UserBindDetail bindPhone = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class) .eq(UserBindDetail::getUserId, userId).last("limit 1")); //手机号 if (bindPhone != null) { userWhoami.setBindPhone(bindPhone.getPhone()); userWhoami.setBindEmail(bindPhone.getEmail()); } Integer type = 3; if (StrUtil.isNotBlank(user.getLoginPhone())) { type = 1; } else if (StrUtil.isNotBlank(user.getEmail())) { type = 2; } userWhoami.setType(type); return userWhoami; } @Override public User getSyncUser(String openId, String unionId, WxSyncLog wxSyncLog) { User user; //迁移公众号之后同步授权后信息 //是否是迁移用户 if (wxSyncLog != null) { user = this.getOne(Wrappers.lambdaQuery(User.class) .ne(User::getUnionid, unionId) .eq(User::getOpenId, wxSyncLog.getOriOpenid()).last("limit 1")); if (user != null) { user.setOpenId(wxSyncLog.getNewOpenid()); } else { // 查询用户是否存在 user = Optional.ofNullable( this.getOne(new LambdaQueryWrapper().eq(User::getUnionid, unionId) .orderByAsc(User::getId) .last("limit 1"))) .orElseGet(() -> this.getOne(new LambdaQueryWrapper().eq(User::getOpenId, openId) .orderByAsc(User::getId) .last("limit 1"))); } } else { // 查询用户是否存在 user = Optional.ofNullable( this.getOne(new LambdaQueryWrapper().eq(User::getUnionid, unionId) .orderByAsc(User::getId) .last("limit 1"))) .orElseGet(() -> this.getOne(new LambdaQueryWrapper().eq(User::getOpenId, openId) .orderByAsc(User::getId) .last("limit 1"))); } return user; } @Override public void sendFixedCustomerCoupon(Long popularizeId, Long userId, String unionId) { //若是百度渠道 添加固定客服 注册后直接发放优惠券 ChannelPopularize channelPopularize = channelPopularizeMapper.selectById(popularizeId); if (channelPopularize != null && channelPopularize.getChannelId() == 34) { // SysConfig corpConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class) // .eq(SysConfig::getSysKey, Constant.CORP_FIXED_CUSTOMER) // .last("limit 1")); // if (corpConfig != null) { // Optional.ofNullable(corpConfig.getSysValue()).ifPresent(value -> { // try { // if (StrUtil.isNotBlank(value)) { // List followIds = Jsons.parseList(value, String.class); // //添加固定客服发放优惠券 // CorpUserFollowView corpUserFollowView = beanSearcher.searchFirst(CorpUserFollowView.class, MapUtils.builder() // .field(CorpUserFollowView::getUnionId, unionId) // .field(CorpUserFollowView::getFollowId, followIds).op(Operator.InList).build()); // if (corpUserFollowView != null) { // Constant.FIXED_CUSTOMER_COUPON_IDS.forEach(couponId -> couponCommonService.sendCouponToUser(userId, couponId, 0l, 0l, 0l, CouponUser.Channel.wxCorp)); // } // } // } catch (Exception e) { // } // }); // // } SysConfig config = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class) .eq(SysConfig::getSysKey, Constant.BAIDU_POPULARIZE_COUPON_IDS).last("limit 1")); if (config != null) { String sysValue = config.getSysValue(); if (StrUtil.isNotBlank(sysValue)) { try { List couponIds = Jsons.parseList(sysValue, Long.class); couponIds.forEach(couponId -> couponCommonService.sendCouponToUser(userId, couponId, 0l, 0l, popularizeId, CouponUser.Channel.manual)); } catch (Exception e) { log.error("百度渠道优惠券解析错误"); } } } } } @Override public List getRelationUserIdList(Long userId, User selectUser) { List userIds = new ArrayList<>(); userIds.add(userId); UserBindDetail userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class) .eq(UserBindDetail::getUserId, userId).last("limit 1")); if (userBindDetail == null) { User user = Optional.ofNullable(selectUser).orElse(this.getById(userId)); if (StrUtil.isEmpty(user.getOpenId()) && StrUtil.isNotEmpty(user.getLoginPhone())) { userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class) .eq(UserBindDetail::getPhone, user.getLoginPhone()).last("limit 1")); if (userBindDetail != null) { userIds.add(userBindDetail.getUserId()); } } } else { if (StrUtil.isNotBlank(userBindDetail.getPhone())) { User otherUser = this.getOne(Wrappers.lambdaQuery(User.class) .eq(User::getLoginPhone, userBindDetail.getPhone()).last("limit 1")); if (otherUser != null) { userIds.add(otherUser.getId()); } } } return userIds; } @Override public List getUserIdsByNickname(String nickname) { return userMapper.selectListByNickname(nickname); } @Override public String getUserShowId(Long userId) { Integer update = 0; String showId = null; while (update != 1) { showId = StringUtil.randomString(5); try { update = userMapper.update(null, Wrappers.lambdaUpdate(User.class) .set(User::getShowId, showId) .eq(User::getId, userId)); } catch (DuplicateKeyException e) { update = 0; } } return showId; } @Override public Long getUserIdByShowId(String showId) { return userMapper.getUserIdByShowId(showId); } @Override public User webLogin(LoginReq loginReq) throws Exception { LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(User.class).last("limit 1"); if (loginReq.getType() == null || loginReq.getType() < 1 && loginReq.getType() > 2) { throw BusinessRuntimeException.getInstance("系统异常,请刷新页面重新操作"); } if (loginReq.getType() == 1) { if (StrUtil.hasEmpty(loginReq.getPhone(), loginReq.getCode())) { throw BusinessRuntimeException.getInstance("请输入对应信息"); } DateTime now = DateTime.now(); PhoneCode phoneCode = phoneCodeMapper.selectOne(Wrappers.lambdaQuery(PhoneCode.class).eq(PhoneCode::getPhone, loginReq.getPhone()).last("limit 1")); if (phoneCode == null || StrUtil.isEmpty(phoneCode.getCode())) { throw BusinessRuntimeException.getInstance("请重新获取手机验证码"); } //3分钟失效 Date updateTime = phoneCode.getUpdateTime(); DateTime afterFiveMinutes = DateUtil.offsetMinute(updateTime, 3); if (now.isAfter(afterFiveMinutes)) { throw BusinessRuntimeException.getInstance("手机验证码已失效,请重新获取"); } if (!StrUtil.equals(loginReq.getCode(), phoneCode.getCode())) { throw BusinessRuntimeException.getInstance("手机验证码错误,请重新输入"); } wrapper.eq(User::getLoginPhone, loginReq.getPhone()); } if (loginReq.getType() == 2) { if (StrUtil.isEmpty(loginReq.getEmail())) { throw BusinessRuntimeException.getInstance("邮箱不能为空"); } String code = redisService.getStr(RedisService.key.EMAIL_CODE_KEY.getNameFormat(loginReq.getEmail())); if (StrUtil.isEmpty(code)) { throw BusinessRuntimeException.getInstance("邮箱验证码已失效,请重新获取"); } if (!StrUtil.equals(loginReq.getCode(), code)) { throw BusinessRuntimeException.getInstance("邮箱验证码错误,请重新输入"); } wrapper.eq(User::getEmail, loginReq.getEmail()); redisService.del(RedisService.key.EMAIL_CODE_KEY.getNameFormat(loginReq.getEmail())); } if (loginReq.getType() == 3){ wrapper.eq(User::getEmail, loginReq.getEmail()); } //保存用户信息 User user = this.getOne(wrapper); String dsCode = loginReq.getDsCode(); Long sharedId = loginReq.getSharedId(); Long dsPopularizeId = null; Integer dsType = loginReq.getDsType(); Boolean isNewUser = false; if (StrUtil.isNotBlank(dsCode)) { dsCode = dsCode.trim(); User sharedUser = this.getOne(Wrappers.lambdaQuery(User.class) .eq(User::getShowId, dsCode).last("limit 1")); if (sharedUser != null) { sharedId = sharedUser.getId(); } else { UserDistributePopularize distributePopularize = distributePopularizeMapper.selectOne(Wrappers.lambdaQuery(UserDistributePopularize.class) .eq(UserDistributePopularize::getCode, dsCode) .select(UserDistributePopularize::getUserId, UserDistributePopularize::getId).last("limit 1")); if (distributePopularize != null) { log.info("渠道sharedId:{}设置固定推广链接PC用户分销", distributePopularize.getUserId()); sharedId = distributePopularize.getUserId(); dsPopularizeId = distributePopularize.getId(); } } } if (user != null && loginReq.getType() == 3 && !user.getIsGoogle()) { user.setIsGoogle(true); this.updateById(user); } if (user == null) { user = new User(); isNewUser = true; StringBuilder name = new StringBuilder(); name.append(Constant.DEFAULT_NAME); if (loginReq.getPopularizeId() != null) { user.setPopularizeId(loginReq.getPopularizeId()); } if (loginReq.getType() == 1) { user.setLoginPhone(loginReq.getPhone()); } if (loginReq.getType() == 2 || loginReq.getType() == 3) { user.setEmail(loginReq.getEmail()); name.append("@"); } if (loginReq.getType() == 3) { user.setIsGoogle(true); } user.setNickname(String.format("%s%s", name.toString(), Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.MD5).setStringData(String.format("%s%s", user.getId(), loginReq.getType() == 1 ? user.getLoginPhone() : user.getEmail())).toHexString().substring(0, 6))); //默认头像 user.setHeadimgurl(Constant.DEFAULT_HEAD_IMG); String registerEnv = loginReq.getRegisterEnv(); user.setRegisterEnv(StrUtil.isEmpty(registerEnv) ? User.RegisterEnv.pc.name() : registerEnv); this.save(user); //新用户分销 if (sharedId != null) { distributeService.saveDistributionInvitation(sharedId, user.getId(), dsPopularizeId); } //缓存用户注册 回传信息 String callback = loginReq.getCallback(); String callbackType = loginReq.getCallbackType(); if (StrUtil.isNotBlank(callback)) { OrderDonPostDataDto orderDonPostDataDto = new OrderDonPostDataDto().setCallback(callback) .setCallbackType(callbackType); redisService.set(RedisService.key.ORDER_DON_POST_DATA_USER_KEY.getName() + user.getId(), Jsons.toJson(orderDonPostDataDto)); } //发放新用户福利 final Long fUid = user.getId(); TASK_POOL.execute(() -> { try { sendNewUserWelfare(fUid); } catch (Exception e) { } }); final String login_email = user.getEmail(); final String login_phone = user.getLoginPhone(); UserBindDetail bindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class) .and(ub -> ub.eq(StrUtil.isNotBlank(login_email), UserBindDetail::getEmail, login_email) .or().eq(StrUtil.isNotBlank(login_phone), UserBindDetail::getPhone, login_phone)) .last("limit 1")); if (bindDetail != null) { if (StrUtil.isNotBlank(login_phone)) { bindDetail.setPhoneUserId(user.getId()); } if (StrUtil.isNotBlank(login_email)) { bindDetail.setEmailUserId(user.getId()); } userBindDetailMapper.updateById(bindDetail); } } if (StrUtil.isEmpty(user.getShowId())) { user.setShowId(getUserShowId(user.getId())); } //新旧用户都可实物分销 if (sharedId != null && dsType != null && dsType == 2) { equipDistributeService.saveDistributionInvitation(sharedId, isNewUser, user.getId()); } return user; } @Override public String bindWxAccountRedirect(String code, String state) throws Exception { AuthToken token = weChatService.getAuthToken(code, wxOpenPlatYHLXLoginConfig.getAppId()); //重定向 // 根据openid 与 access_token 获取用户信息 GzhOAuth2UserInfo userinfo = weChatService.getUserInfo(token.getAccessToken(), token.getOpenid()); // 转跳参数 String json = Codec.DoBase64.custom().setData(state).decodeAsText(); AuthRedirect re = Jsons.parseObject(json, AuthRedirect.class); //保存用户信息 User user = saveAuth(userinfo, re.getSharedId(), re.getDsType(), re.getPid(), User.RegisterEnv.pc, re.getDsCode(), re.getCk(), re.getCt()); if (user == null) { throw BusinessRuntimeException.getInstance("系统错误,请重新授权"); } String loginPhone = re.getLp(); String loginEmail = re.getLe(); if (StrUtil.isNotBlank(loginPhone)) { log.info("手机号phone:{}登录用户,微信扫描网页授权二维码进行用户信息绑定", loginPhone); try { bindTaskService.bindPhone(user, loginPhone, null); } catch (Exception e) { log.info(StringUtil.getErrorText(e)); } } if (StrUtil.isNotBlank(loginEmail)) { log.info("邮箱email:{}登录用户,微信扫描网页授权二维码进行用户信息绑定", loginEmail); try { bindTaskService.bindEmail(user, loginEmail, null); } catch (Exception e) { log.info(StringUtil.getErrorText(e)); } } return redisService.getStr(re.getMappingId().toString()); } /** * 发放新用户福利 */ public void sendNewUserWelfare(Long userId) throws Exception { SysConfig newUserWelfareConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class) .eq(SysConfig::getSysKey, Constant.NEW_USER_WELFARE_KEY).last("limit 1")); if (StrUtil.isEmpty(newUserWelfareConfig.getSysValue())) { return; } NewUserWelfareDto newUserWelfareDto = Jsons.parseObject(newUserWelfareConfig.getSysValue(), NewUserWelfareDto.class); if (newUserWelfareDto != null) { List couponIds = newUserWelfareDto.getCouponIds(); couponIds.forEach(couponId -> couponCommonService.sendCouponToUser(userId, couponId, null, null, null, CouponUser.Channel.new_welfare)); } } }