소스 검색

绑定其他用户信息

zoujiajian 3 년 전
부모
커밋
6b02627e16
24개의 변경된 파일672개의 추가작업 그리고 133개의 파일을 삭제
  1. 5 0
      netflix-dao/src/main/java/com/cyksj/model/dto/GzhBodyDto.java
  2. 5 0
      netflix-dao/src/main/java/com/cyksj/model/dto/UserWhoami.java
  3. 7 0
      netflix-dao/src/main/java/com/cyksj/model/entity/User.java
  4. 4 0
      netflix-dao/src/main/java/com/cyksj/model/entity/UserBindDetail.java
  5. 28 0
      netflix-dao/src/main/java/com/cyksj/model/request/UserBindInfoReq.java
  6. 1 1
      netflix-dao/src/main/java/com/cyksj/model/response/UserAuthLoginResp.java
  7. 35 0
      netflix-dao/src/main/java/com/cyksj/model/views/UserBindAccountView.java
  8. 1 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  9. 16 8
      netflix-service/src/main/java/com/cyksj/service/gzh/factory/EventMsgService.java
  10. 22 7
      netflix-service/src/main/java/com/cyksj/service/market/task/BindTaskService.java
  11. 295 27
      netflix-service/src/main/java/com/cyksj/service/market/task/impl/BindTaskServiceImpl.java
  12. 6 4
      netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java
  13. 18 0
      netflix-service/src/main/java/com/cyksj/service/user/UserBindRelationService.java
  14. 1 4
      netflix-service/src/main/java/com/cyksj/service/user/UserService.java
  15. 87 0
      netflix-service/src/main/java/com/cyksj/service/user/impl/UserBindRelationServiceImpl.java
  16. 23 2
      netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java
  17. 5 2
      netflix-service/src/main/java/com/cyksj/service/user/impl/WorkOrderFrontServiceImpl.java
  18. 1 1
      netflix-service/src/main/java/com/cyksj/service/wechat/WeChatService.java
  19. 3 2
      netflix-service/src/main/java/com/cyksj/service/wechat/impl/WeChatServiceImpl.java
  20. 8 5
      netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java
  21. 37 47
      netflix-web/src/main/java/com/cyksj/web/controller/market/TaskFrontController.java
  22. 3 3
      netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java
  23. 16 13
      netflix-web/src/main/java/com/cyksj/web/controller/user/AuthorizationController.java
  24. 45 7
      netflix-web/src/main/java/com/cyksj/web/controller/user/UserController.java

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/GzhBodyDto.java

@@ -34,6 +34,11 @@ public class GzhBodyDto {
 	 */
 	private String loginPhone;
 
+	/**
+	 * 登录邮箱
+	 */
+	private String loginEmail;
+
 	/**
 	 * 固定推广code
 	 */

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/UserWhoami.java

@@ -33,6 +33,11 @@ public class UserWhoami implements Serializable {
 
     private String email;
 
+    /**
+     * 1、手机号,2、邮箱,3、微信
+     */
+    private Integer type;
+
     private String bindPhone;
 
     private String bindEmail;

+ 7 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/User.java

@@ -1,5 +1,6 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.experimental.Accessors;
@@ -84,6 +85,12 @@ public class User extends BaseEntity implements Serializable{
      */
     private Date lastTime;
 
+    @TableField(exist = false)
+    private Long emailUserId;
+
+    @TableField(exist = false)
+    private Long phoneUserId;
+
     @Getter
     public enum RegisterEnv{
         wx("公众号h5授权登录"),

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserBindDetail.java

@@ -16,5 +16,9 @@ public class UserBindDetail extends BaseEntity{
 
 	private String phone;
 
+	private Long phoneUserId;
+
 	private String email;
+
+	private Long emailUserId;
 }

+ 28 - 0
netflix-dao/src/main/java/com/cyksj/model/request/UserBindInfoReq.java

@@ -0,0 +1,28 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/*
+ *项目名: netflix
+ *文件名: UserBindInfoReq
+ *创建者: JavaZou
+ *创建时间:2023/7/31 17:33
+ */
+@Getter
+@Setter
+public class UserBindInfoReq {
+	/**
+	 * 1、手机号、2、邮箱、3、微信
+	 */
+	@NotNull
+	private Integer type;
+
+	private String account;
+
+	private Long userId;
+
+	private String code;
+}

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/model/response/LoginPhoneRep.java → netflix-dao/src/main/java/com/cyksj/model/response/UserAuthLoginResp.java

@@ -15,7 +15,7 @@ import lombok.Setter;
 @Setter
 @AllArgsConstructor
 @NoArgsConstructor
-public class LoginPhoneRep {
+public class UserAuthLoginResp {
 	private String saToken;
 
 	private String showId;

+ 35 - 0
netflix-dao/src/main/java/com/cyksj/model/views/UserBindAccountView.java

@@ -0,0 +1,35 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: UserBindAccountView
+ *创建者: JavaZou
+ *创建时间:2023/8/1 15:37
+ */
+@Getter
+@Setter
+@SearchBean(tables = "user u")
+public class UserBindAccountView {
+	@DbField("u.id")
+	private Long userId;
+
+	@DbField("u.nickname")
+	private String nickname;
+
+	@DbField("u.headimgurl")
+	private String img;
+
+	@DbField("case when login_phone != '' then login_phone when email != '' then email else null end")
+	private String account;
+
+	/**
+	 * 1手机号 2、邮箱 3、微信
+	 */
+	@DbField("case when login_phone != '' then 1 when email != '' then 2 else 3 end")
+	private Integer type;
+}

+ 1 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -629,6 +629,7 @@ public class RedisService {
         ORDER_DON_POST_DATA_USER_KEY("order_don_post_data_user_key:", "用户订单回传缓存key", -1L),
         ABROAD_SUCCESS_URL("abroad:pay:success_url:","海外支付成功页",60 * 60 * 24L),
         CHAT_GPT_TOKEN_KEY("chat_gpt_token_key:", "chatGPT直连token key", 60 * 10l),
+        USER_BIND_ACCOUNT_INFO_KEY("user_bind_account_info_key:", "用户绑定其他账号key", 10l),
         ;
 
         private String name;

+ 16 - 8
netflix-service/src/main/java/com/cyksj/service/gzh/factory/EventMsgService.java

@@ -183,8 +183,7 @@ public class EventMsgService implements GzhMsgService {
 						userService.sendFixedCustomerCoupon(popularizeId, userId, info.getUnionid());
 					});
 				}
-				String loginPhone = gzhDto.getLoginPhone();
-				userBind(user.getId(), sceneKey, loginPhone);
+				userBind(user, sceneKey, gzhDto.getLoginPhone(), gzhDto.getLoginEmail());
 			}
 
 			saveGzhUserRelation(msgEvent, user.getId(), openId, info.getUnionid(), sceneKey, wxApp.getId());
@@ -196,8 +195,7 @@ public class EventMsgService implements GzhMsgService {
 			}
 			saveGzhUserRelation(msgEvent, user.getId(), openId, info.getUnionid(), sceneKey, wxApp.getId());
 			if (gzhDto != null) {
-				String loginPhone = gzhDto.getLoginPhone();
-				userBind(user.getId(), sceneKey, loginPhone);
+				userBind(user, sceneKey, gzhDto.getLoginPhone(), gzhDto.getLoginEmail());
 			}
 		}
 		//场景值扫描公众号二维码 登录
@@ -243,12 +241,22 @@ public class EventMsgService implements GzhMsgService {
 		}
 	}
 
-	public void userBind(Long userId, String sceneKey, String loginPhone) {
+	public void userBind(User user, String sceneKey, String loginPhone, String loginEmail) {
 		if (StrUtil.isNotBlank(loginPhone)) {
-			log.info("pc端用户phone:{}购买车票后,微信扫描公众号二维码进行用户信息绑定", loginPhone);
+			log.info("手机号phone:{}登录用户,微信扫描公众号二维码进行用户信息绑定", loginPhone);
 			try {
-				bindTaskService.bindPhone(userId, loginPhone, null, false);
-				redisService.set(RedisService.key.WX_GZH_QRCODE_BIND.getNameFormat(sceneKey), userId, RedisService.key.WX_GZH_QRCODE_BIND.getTimeout());
+				bindTaskService.bindPhone(user, loginPhone, null);
+				redisService.set(RedisService.key.WX_GZH_QRCODE_BIND.getNameFormat(sceneKey), user.getId(), RedisService.key.WX_GZH_QRCODE_BIND.getTimeout());
+			} catch (Exception e) {
+				log.info(StringUtil.getErrorText(e));
+			}
+		}
+
+		if (StrUtil.isNotBlank(loginEmail)) {
+			log.info("邮箱email:{}登录用户,微信扫描公众号二维码进行用户信息绑定", loginEmail);
+			try {
+				bindTaskService.bindEmail(user, loginEmail, null);
+				redisService.set(RedisService.key.WX_GZH_QRCODE_BIND.getNameFormat(sceneKey), user.getId(), RedisService.key.WX_GZH_QRCODE_BIND.getTimeout());
 			} catch (Exception e) {
 				log.info(StringUtil.getErrorText(e));
 			}

+ 22 - 7
netflix-service/src/main/java/com/cyksj/service/market/task/BindTaskService.java

@@ -1,5 +1,10 @@
 package com.cyksj.service.market.task;
 
+import com.cyksj.dto.Result;
+import com.cyksj.model.entity.User;
+import com.cyksj.model.entity.UserBindDetail;
+import com.cyksj.model.request.UserBindInfoReq;
+
 /*
  *项目名: netflix
  *文件名: BindTaskService
@@ -9,13 +14,23 @@ package com.cyksj.service.market.task;
 public interface BindTaskService {
 
 	/**
-	 *
-	 * @param userId 用户id
-	 * @param phone 绑定手机号
-	 * @param code 验证码
-	 * @param isCode 是否需要验证码 true需要
+	 * @param user        用户
+	 * @param phone       绑定手机号
+	 * @param code        验证码
 	 */
-	void bindPhone(Long userId, String phone, String code, Boolean isCode);
+	UserBindDetail bindPhone(User user, String phone, String code);
+
+	void updateBindPhone(User user, String phone, String code);
+
+	UserBindDetail bindEmail(User user, String email, String code);
+
+	Result<Object> bindOtherAccount(UserBindInfoReq request) throws Exception;
+
+	void updateBindAccount(UserBindInfoReq request);
+
+	void updateBindEmail(User user, String email, String inputCode);
+
+	void checkPhoneCode(String phone, String inputCode);
 
-	void updateBindPhone(Long userId, String phone, String code);
+	void checkEmailCode(String email, String inputCode);
 }

+ 295 - 27
netflix-service/src/main/java/com/cyksj/service/market/task/impl/BindTaskServiceImpl.java

@@ -1,20 +1,34 @@
 package com.cyksj.service.market.task.impl;
 
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.constant.TaskTypeEnum;
 import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayApiCode;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.PhoneCodeMapper;
+import com.cyksj.mapper.UserMapper;
 import com.cyksj.mapper.market.task.TaskTypeMapper;
 import com.cyksj.mapper.market.task.UserBindDetailMapper;
+import com.cyksj.model.entity.PhoneCode;
 import com.cyksj.model.entity.TaskType;
+import com.cyksj.model.entity.User;
 import com.cyksj.model.entity.UserBindDetail;
+import com.cyksj.model.request.UserBindInfoReq;
+import com.cyksj.model.response.WxGzhQrCodeTicketRep;
+import com.cyksj.redis.RedisService;
 import com.cyksj.service.market.task.BindTaskService;
 import com.cyksj.service.market.task.TaskService;
-import com.cyksj.service.phone.PhoneCodeService;
+import com.cyksj.service.wechat.WeChatService;
 import lombok.RequiredArgsConstructor;
-import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
 import java.util.Optional;
 
 /*
@@ -30,58 +44,312 @@ public class BindTaskServiceImpl implements BindTaskService {
 
 	private final TaskTypeMapper taskTypeMapper;
 
-	private final PhoneCodeService phoneCodeService;
+	private final UserBindDetailMapper userBindDetailMapper;
 
-	private final UserBindDetailMapper UserBindDetailMapper;
+	private final RedisService redisService;
 
+	private final PhoneCodeMapper phoneCodeMapper;
+
+	private final UserMapper userMapper;
+
+	private final WeChatService weChatService;
 
 	@Override
-	public void bindPhone(Long userId, String phone, String code, Boolean isCode) {
-		UserBindDetail other = UserBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
-				.eq(UserBindDetail::getPhone, phone).ne(UserBindDetail::getUserId, userId).select(UserBindDetail::getId).last("limit 1"));
-		if (other != null) {
-			throw BusinessRuntimeException.getInstance("该手机号已被绑定");
+	public UserBindDetail bindPhone(User user, String phone, String code) {
+		Long userId = user.getId();
+		if (!Validator.isMobile(phone)) {
+			throw BusinessRuntimeException.getInstance("请输入正确的手机号");
+		}
+		if (StrUtil.isNotBlank(user.getLoginPhone())) {
+			throw BusinessRuntimeException.getInstance("您通过手机号登录,无法绑定其他手机号");
 		}
-		UserBindDetail bindPhone = Optional.ofNullable(UserBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
-				.eq(UserBindDetail::getUserId, userId).last("limit 1"))).orElse(new UserBindDetail());
+		LambdaQueryWrapper<UserBindDetail> wrapper = Wrappers.lambdaQuery(UserBindDetail.class)
+				.eq(StrUtil.isNotBlank(user.getEmail()), UserBindDetail::getEmail, user.getEmail())
+				.eq(StrUtil.isNotBlank(user.getOpenId()), UserBindDetail::getUserId, user.getId())
+				.last("limit 1");
+
+		UserBindDetail bindPhone = Optional.ofNullable(userBindDetailMapper.selectOne(wrapper)).orElse(new UserBindDetail());
 		if (StrUtil.isNotBlank(bindPhone.getPhone())) {
 			throw BusinessRuntimeException.getInstance("您已绑定手机号");
 		}
-		if (isCode) {
+
+		UserBindDetail other = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+				.eq(UserBindDetail::getPhone, phone)
+				.select(UserBindDetail::getId)
+				.last("limit 1"));
+		if (other != null) {
+			throw BusinessRuntimeException.getInstance("该手机号已被绑定");
+		}
+
+		if (StrUtil.isNotBlank(code)) {
 			//校验
-			phoneCodeService.checkPhone(phone, code);
+			checkPhoneCode(phone, code);
+		}
+		if (StrUtil.isNotBlank(user.getOpenId())) {
+			bindPhone.setUserId(userId);
+		}
+		if (StrUtil.isNotBlank(user.getEmail())) {
+			bindPhone.setEmailUserId(userId);
+			bindPhone.setEmail(user.getEmail());
+		}
+		if (bindPhone.getPhoneUserId() == null) {
+			Long phoneUserId = user.getPhoneUserId();
+			if (phoneUserId == null) {
+				User phoneUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+						.eq(User::getLoginPhone, phone).last("limit 1"));
+				if (phoneUser != null) {
+					phoneUserId = phoneUser.getId();
+				}
+			}
+			bindPhone.setPhoneUserId(phoneUserId);
 		}
-		bindPhone.setUserId(userId);
 		bindPhone.setPhone(phone);
-		try {
-			if (bindPhone.getId() == null) {
-				UserBindDetailMapper.insert(bindPhone);
-			} else {
-				UserBindDetailMapper.updateById(bindPhone);
+		if (bindPhone.getId() == null) {
+			if (redisService.setNx(RedisService.key.USER_BIND_ACCOUNT_INFO_KEY.getName() + phone, phone, RedisService.key.USER_BIND_ACCOUNT_INFO_KEY.getTimeout())) {
+				userBindDetailMapper.insert(bindPhone);
 			}
-		} catch (DuplicateKeyException e) {
-
+		} else {
+			userBindDetailMapper.updateById(bindPhone);
 		}
 		TaskType taskType = taskTypeMapper.selectOne(Wrappers.lambdaQuery(TaskType.class)
 				.eq(TaskType::getName, TaskTypeEnum.bind_phone.getDesc()).last("limit 1"));
 		//完成任务
 		taskService.completeTask(taskType, userId);
+		return bindPhone;
 	}
 
 	@Override
-	public void updateBindPhone(Long userId, String phone, String code) {
-		UserBindDetail bindPhone = UserBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
-				.eq(UserBindDetail::getUserId, userId).last("limit 1"));
+	public void updateBindPhone(User user, String phone, String code) {
+		Long userId = user.getId();
+		LambdaQueryWrapper<UserBindDetail> wrapper = Wrappers.lambdaQuery(UserBindDetail.class).last("limit 1");
+		if (StrUtil.isNotBlank(user.getLoginPhone())) {
+			throw BusinessRuntimeException.getInstance("无法更换自身登录手机号");
+		}
+		if (StrUtil.isNotBlank(user.getOpenId())) {
+			wrapper.eq(UserBindDetail::getUserId, userId);
+		}
+		if (StrUtil.isNotBlank(user.getEmail())) {
+			wrapper.eq(UserBindDetail::getEmail, user.getEmail());
+		}
+		UserBindDetail bindPhone = userBindDetailMapper.selectOne(wrapper);
 		if (bindPhone == null || StrUtil.isEmpty(bindPhone.getPhone())) {
 			throw BusinessRuntimeException.getInstance("您未绑定手机号");
 		}
-		UserBindDetail other = UserBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+		if (bindPhone.getPhone().equals(phone)) {
+			throw BusinessRuntimeException.getInstance("换绑手机号重复");
+		}
+		UserBindDetail other = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
 				.eq(UserBindDetail::getPhone, phone).ne(UserBindDetail::getUserId, userId).select(UserBindDetail::getId).last("limit 1"));
 		if (other != null) {
 			throw BusinessRuntimeException.getInstance("该手机号已被绑定");
 		}
-		phoneCodeService.checkPhone(phone, code);
+		User phoneUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+				.eq(User::getLoginPhone, phone).last("limit 1"));
+		if (phoneUser == null) {
+			throw BusinessRuntimeException.getInstance("换绑手机号重复未注册");
+		}
+		checkPhoneCode(phone, code);
+		bindPhone.setPhoneUserId(phoneUser.getId());
 		bindPhone.setPhone(phone);
-		UserBindDetailMapper.updateById(bindPhone);
+
+		userBindDetailMapper.update(null, Wrappers.lambdaUpdate(UserBindDetail.class)
+				.set(UserBindDetail::getPhone, phone)
+				.set(UserBindDetail::getPhoneUserId, bindPhone.getPhoneUserId())
+				.eq(UserBindDetail::getId, bindPhone.getId()));
+	}
+
+	@Override
+	public void updateBindEmail(User user, String email, String inputCode) {
+		Long userId = user.getId();
+		LambdaQueryWrapper<UserBindDetail> wrapper = Wrappers.lambdaQuery(UserBindDetail.class).last("limit 1");
+		if (StrUtil.isNotBlank(user.getEmail())) {
+			throw BusinessRuntimeException.getInstance("无法更换自身登录邮箱");
+		}
+		if (StrUtil.isNotBlank(user.getOpenId())) {
+			wrapper.eq(UserBindDetail::getUserId, userId);
+		}
+		if (StrUtil.isNotBlank(user.getLoginPhone())) {
+			wrapper.eq(UserBindDetail::getPhone, user.getLoginPhone());
+		}
+		UserBindDetail bindDetail = userBindDetailMapper.selectOne(wrapper);
+		if (bindDetail == null || StrUtil.isEmpty(bindDetail.getEmail())) {
+			throw BusinessRuntimeException.getInstance("您未绑定邮箱");
+		}
+		if (bindDetail.getEmail().equals(email)) {
+			throw BusinessRuntimeException.getInstance("换绑邮箱重复");
+		}
+		UserBindDetail other = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+				.eq(UserBindDetail::getEmail, email).ne(UserBindDetail::getUserId, userId).select(UserBindDetail::getId).last("limit 1"));
+		if (other != null) {
+			throw BusinessRuntimeException.getInstance("该邮箱已被绑定");
+		}
+		checkEmailCode(email, inputCode);
+		User emailUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+				.eq(User::getEmail, email).last("limit 1"));
+		if (emailUser == null) {
+			throw BusinessRuntimeException.getInstance("绑定的邮箱未注册");
+		}
+		bindDetail.setEmailUserId(emailUser.getId());
+		bindDetail.setEmail(email);
+
+		userBindDetailMapper.update(null, Wrappers.lambdaUpdate(UserBindDetail.class)
+				.set(UserBindDetail::getEmail, email)
+				.set(UserBindDetail::getEmailUserId, bindDetail.getEmailUserId())
+				.eq(UserBindDetail::getId, bindDetail.getId()));
+	}
+
+	@Override
+	public UserBindDetail bindEmail(User user, String account, String inputCode) {
+		Long userId = user.getId();
+		if (!Validator.isEmail(account)) {
+			throw BusinessRuntimeException.getInstance("请输入正确的邮箱");
+		}
+		if (StrUtil.isNotBlank(user.getEmail())) {
+			throw BusinessRuntimeException.getInstance("您通过邮箱登录,无法绑定其他邮箱");
+		}
+		LambdaQueryWrapper<UserBindDetail> wrapper = Wrappers.lambdaQuery(UserBindDetail.class)
+				.eq(StrUtil.isNotBlank(user.getLoginPhone()), UserBindDetail::getPhone, user.getLoginPhone())
+				.eq(StrUtil.isNotBlank(user.getOpenId()), UserBindDetail::getUserId, user.getId())
+				.last("limit 1");
+		UserBindDetail bindPhone = Optional.ofNullable(userBindDetailMapper.selectOne(wrapper)).orElse(new UserBindDetail());
+		if (StrUtil.isNotBlank(bindPhone.getEmail())) {
+			throw BusinessRuntimeException.getInstance("您已绑定邮箱");
+		}
+
+		UserBindDetail other = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+				.eq(UserBindDetail::getEmail, account)
+				.select(UserBindDetail::getId)
+				.last("limit 1"));
+		if (other != null) {
+			throw BusinessRuntimeException.getInstance("该邮箱已被绑定");
+		}
+
+		if (StrUtil.isNotBlank(inputCode)) {
+			checkEmailCode(account, inputCode);
+		}
+		bindPhone.setEmail(account);
+		if (StrUtil.isNotBlank(user.getOpenId())) {
+			bindPhone.setUserId(userId);
+		}
+		if (StrUtil.isNotBlank(user.getLoginPhone())) {
+			bindPhone.setPhoneUserId(userId);
+			bindPhone.setPhone(user.getLoginPhone());
+		}
+		if (bindPhone.getEmailUserId() == null) {
+			Long emailUserId = user.getEmailUserId();
+			if (emailUserId == null) {
+				User emailUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+						.eq(User::getEmail, account).last("limit 1"));
+				if (emailUser != null) {
+					emailUserId = emailUser.getId();
+				}
+			}
+			bindPhone.setEmailUserId(emailUserId);
+		}
+		if (bindPhone.getId() == null) {
+			if (redisService.setNx(RedisService.key.USER_BIND_ACCOUNT_INFO_KEY.getName() + account, account, RedisService.key.USER_BIND_ACCOUNT_INFO_KEY.getTimeout())) {
+				userBindDetailMapper.insert(bindPhone);
+			}
+		} else {
+			userBindDetailMapper.updateById(bindPhone);
+		}
+		redisService.del(RedisService.key.EMAIL_CODE_KEY.getNameFormat(account));
+		return bindPhone;
+	}
+
+	@Override
+	public Result<Object> bindOtherAccount(UserBindInfoReq request) throws Exception {
+		Long userId = request.getUserId();
+		User user = userMapper.selectById(userId);
+		Integer type = request.getType();
+		if (type == null) throw BusinessRuntimeException.getInstance("绑定类型为空");
+
+		if (user == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
+		String account = request.getAccount();
+		String code = request.getCode();
+		if (type != 3 && (StrUtil.isEmpty(account) || StrUtil.isEmpty(code))) {
+			throw BusinessRuntimeException.getInstance("请输入正确的绑定信息");
+		}
+		if (type == 1) {
+			if (StrUtil.isNotBlank(user.getLoginPhone())) {
+				throw BusinessRuntimeException.getInstance("您通过手机号登录,无法绑定其他手机号");
+			}
+			User phoneUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+					.eq(User::getLoginPhone, account).last("limit 1"));
+			if (phoneUser == null) {
+				throw BusinessRuntimeException.getInstance("绑定的手机号未注册");
+			}
+			user.setPhoneUserId(phoneUser.getId());
+			bindPhone(user, account, code);
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		if (type == 2) {
+			if (StrUtil.isNotBlank(user.getEmail())) {
+				throw BusinessRuntimeException.getInstance("您通过邮箱登录,无法绑定其他邮箱");
+			}
+			User emailUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+					.eq(User::getEmail, account).last("limit 1"));
+			if (emailUser == null) {
+				throw BusinessRuntimeException.getInstance("绑定的邮箱未注册");
+			}
+			user.setEmailUserId(emailUser.getId());
+			bindEmail(user, account, code);
+			return GatewayResponse.SUCCESS.newBuilder().toResult();
+		}
+		if (type == 3) {
+			if (StrUtil.isNotBlank(user.getOpenId())) {
+				throw BusinessRuntimeException.getInstance("您通过微信登录,无法绑定其他微信");
+			}
+			//绑定微信 获取临时带参数二维码
+			//获取gzh带参数的二维码
+			WxGzhQrCodeTicketRep result = weChatService.getWxGzhQrCode(null, null, null, user.getLoginPhone(), user.getEmail(), null);
+			return GatewayResponse.SUCCESS.newBuilder().toResult(result);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	@Override
+	public void updateBindAccount(UserBindInfoReq request) {
+		Long userId = request.getUserId();
+		User user = userMapper.selectById(userId);
+		String account = request.getAccount();
+		String code = request.getCode();
+		if (Validator.isMobile(account)) {
+			updateBindPhone(user, account, code);
+			return;
+		}
+		if (Validator.isEmail(account)) {
+			updateBindEmail(user, account, code);
+		}
+
+	}
+
+	@Override
+	public void checkPhoneCode(String phone, String inputCode) {
+		DateTime now = DateTime.now();
+		PhoneCode phoneCode = phoneCodeMapper.selectOne(Wrappers.lambdaQuery(PhoneCode.class).eq(PhoneCode::getPhone, phone).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(inputCode, phoneCode.getCode())) {
+			throw BusinessRuntimeException.getInstance("手机验证码错误,请重新输入");
+		}
+	}
+
+	@Override
+	public void checkEmailCode(String email, String inputCode) {
+		String code = redisService.getStr(RedisService.key.EMAIL_CODE_KEY.getNameFormat(email));
+		if (StrUtil.isEmpty(code)) {
+			throw BusinessRuntimeException.getInstance("邮箱验证码已失效,请重新获取");
+		}
+		if (!StrUtil.equals(inputCode, code)) {
+			throw BusinessRuntimeException.getInstance("邮箱验证码错误,请重新输入");
+		}
 	}
 }

+ 6 - 4
netflix-service/src/main/java/com/cyksj/service/relation/impl/GroupRelationFrontServiceImpl.java

@@ -10,12 +10,14 @@ import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.enums.GatewayApiCode;
 import com.cyksj.mapper.GroupsRelationMapper;
 import com.cyksj.mapper.UserMapper;
-import com.cyksj.model.entity.*;
+import com.cyksj.model.entity.CouponUser;
+import com.cyksj.model.entity.GroupsRelation;
+import com.cyksj.model.entity.User;
 import com.cyksj.model.views.*;
 import com.cyksj.service.chatgpt.ChatGptAuthService;
 import com.cyksj.service.mange.coupon.CouponCommonService;
 import com.cyksj.service.relation.GroupRelationFrontService;
-import com.cyksj.service.user.UserService;
+import com.cyksj.service.user.UserBindRelationService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.param.Operator;
 import com.ejlchina.searcher.util.MapUtils;
@@ -37,7 +39,7 @@ import java.util.stream.Collectors;
 @RequiredArgsConstructor
 @Slf4j
 public class GroupRelationFrontServiceImpl implements GroupRelationFrontService {
-	private final UserService userService;
+	private final UserBindRelationService userBindRelationService;
 
 	private final UserMapper userMapper;
 
@@ -56,7 +58,7 @@ public class GroupRelationFrontServiceImpl implements GroupRelationFrontService
 		if (u.getIsBlack()) {
 			return new ArrayList<>();
 		}
-		List<Long> userIds = userService.getRelationUserIdList(userId, u);
+		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, u);
 		List<RenewalView> list = beanSearcher.searchAll(RenewalView.class, MapUtils.builder()
 				.field(RenewalView::getUserId, 0).op(Operator.GreaterThan)
 				.field(RenewalView::getUserId, userIds).op(Operator.InList)

+ 18 - 0
netflix-service/src/main/java/com/cyksj/service/user/UserBindRelationService.java

@@ -0,0 +1,18 @@
+package com.cyksj.service.user;
+
+import com.cyksj.model.entity.User;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: UserBindRelationService
+ *创建者: JavaZou
+ *创建时间:2023/8/1 15:03
+ */
+public interface UserBindRelationService {
+	/**
+	 * 获取关联用户id集合
+	 */
+	List<Long> getRelationUserIdList(Long userId, User selectUser);
+}

+ 1 - 4
netflix-service/src/main/java/com/cyksj/service/user/UserService.java

@@ -26,10 +26,7 @@ public interface UserService extends IService<User> {
      */
     void sendFixedCustomerCoupon(Long popularizeId, Long userId, String unionId);
 
-    /**
-     * 获取关联用户id集合
-     */
-    List<Long> getRelationUserIdList(Long userId, User selectUser);
+	List<Long> getRelationUserIdList(Long userId, User selectUser);
 
 	List<Long> getUserIdsByNickname(String nickname);
 

+ 87 - 0
netflix-service/src/main/java/com/cyksj/service/user/impl/UserBindRelationServiceImpl.java

@@ -0,0 +1,87 @@
+package com.cyksj.service.user.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.enums.GatewayApiCode;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.market.task.UserBindDetailMapper;
+import com.cyksj.model.entity.User;
+import com.cyksj.model.entity.UserBindDetail;
+import com.cyksj.service.user.UserBindRelationService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: UserBindRelationServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/8/1 15:03
+ */
+@Service
+@RequiredArgsConstructor
+public class UserBindRelationServiceImpl implements UserBindRelationService {
+
+	private final UserBindDetailMapper userBindDetailMapper;
+
+	private final UserMapper userMapper;
+
+	@Override
+	public List<Long> getRelationUserIdList(Long userId, User selectUser) {
+		List<Long> userIds = new ArrayList<>();
+		User user = Optional.ofNullable(selectUser).orElse(userMapper.selectById(userId));
+		if (user == null) throw BusinessRuntimeException.getGatewayApiCode(GatewayApiCode.CMS_TOKEN_VALID);
+
+		UserBindDetail userBindDetail;
+		//微信用户
+		if (StrUtil.isNotEmpty(user.getOpenId())) {
+			userIds.add(userId);
+			userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+					.eq(UserBindDetail::getUserId, userId).last("limit 1"));
+			if (userBindDetail == null) {
+				return userIds;
+			}
+			if (userBindDetail.getPhoneUserId() != null) {
+				userIds.add(userBindDetail.getPhoneUserId());
+			}
+			if (userBindDetail.getEmailUserId() != null) {
+				userIds.add(userBindDetail.getEmailUserId());
+			}
+			return userIds;
+		}
+		Long phoneUserId = null;
+		Long emailUserId = null;
+		if (StrUtil.isNotBlank(user.getLoginPhone())) {
+			phoneUserId = user.getId();
+		}
+		if (StrUtil.isNotBlank(user.getEmail())) {
+			emailUserId = user.getId();
+		}
+		//非微信用户
+		userBindDetail = userBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
+				.eq(phoneUserId != null, UserBindDetail::getPhoneUserId, phoneUserId)
+				.eq(emailUserId != null, UserBindDetail::getEmailUserId, emailUserId)
+				.last("limit 1"));
+		if (userBindDetail == null) {
+			userIds.add(userId);
+			return userIds;
+		}
+		phoneUserId = userBindDetail.getPhoneUserId();
+		emailUserId = userBindDetail.getEmailUserId();
+		Long wxUserId = userBindDetail.getUserId();
+		if (wxUserId != null) {
+			userIds.add(wxUserId);
+		}
+		if (phoneUserId != null) {
+			userIds.add(phoneUserId);
+		}
+		if (emailUserId != null) {
+			userIds.add(emailUserId);
+		}
+		return userIds;
+	}
+}

+ 23 - 2
netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java

@@ -19,8 +19,8 @@ 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.GzhOAuth2UserInfo;
-import com.cyksj.model.dto.OrderDonPostDataDto;
 import com.cyksj.model.dto.NewUserWelfareDto;
+import com.cyksj.model.dto.OrderDonPostDataDto;
 import com.cyksj.model.dto.UserWhoami;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.request.LoginReq;
@@ -179,6 +179,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 		    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;
     }
@@ -416,6 +423,21 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 				} 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()));
@@ -423,7 +445,6 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 		return user;
 	}
 
-
 	/**
 	 * 发放新用户福利
 	 */

+ 5 - 2
netflix-service/src/main/java/com/cyksj/service/user/impl/WorkOrderFrontServiceImpl.java

@@ -15,6 +15,7 @@ import com.cyksj.model.entity.WorkOrderChatHistory;
 import com.cyksj.model.request.WorkOrderReq;
 import com.cyksj.model.views.CmsUserVO;
 import com.cyksj.model.views.GroupRelationDetailView;
+import com.cyksj.service.user.UserBindRelationService;
 import com.cyksj.service.user.UserService;
 import com.cyksj.service.user.WorkOrderFrontService;
 import com.ejlchina.searcher.BeanSearcher;
@@ -48,6 +49,8 @@ public class WorkOrderFrontServiceImpl implements WorkOrderFrontService {
 
 	private final AccountMapper accountMapper;
 
+	private final UserBindRelationService userBindRelationService;
+
 	@Override
 	@Transactional(rollbackFor = Throwable.class)
 	public void submitWorkOrder(WorkOrderReq workOrderReq) {
@@ -75,7 +78,7 @@ public class WorkOrderFrontServiceImpl implements WorkOrderFrontService {
 		if (StrUtil.isNotBlank(imgs) && imgs.length() > 2000) {
 			throw BusinessRuntimeException.getInstance("图片过多");
 		}
-		List<Long> userIds = userService.getRelationUserIdList(userId, user);
+		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, user);
 		GroupRelationDetailView detailView = beanSearcher.searchFirst(GroupRelationDetailView.class, MapUtils.builder()
 				.field(GroupRelationDetailView::getUserId, userIds).op(Operator.InList)
 				.field(GroupRelationDetailView::getRelationId, relationId)
@@ -117,7 +120,7 @@ public class WorkOrderFrontServiceImpl implements WorkOrderFrontService {
 		WorkOrder workOrder = workOrderMapper.selectById(workOrderId);
 		if (workOrder == null) throw BusinessRuntimeException.getInstance("该工单不存在");
 		if (workOrder.getStatus() == WorkOrder.Status.close) throw BusinessRuntimeException.getInstance("本次对话已结束,如有问题请提交新的工单");
-		List<Long> userIds = userService.getRelationUserIdList(userId, user);
+		List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, user);
 		if (!userIds.contains(workOrder.getUserId())) throw BusinessRuntimeException.getInstance("网络错误");
 		String content = history.getContent();
 		String imgs = history.getImgs();

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/wechat/WeChatService.java

@@ -78,7 +78,7 @@ public interface WeChatService {
      * 获取公众号带参数的临时二维码
      * @return
      */
-    WxGzhQrCodeTicketRep getWxGzhQrCode(Long sharedId, Integer dsType, Long popularizeId, String loginPhone, String dsCode) throws Exception;
+    WxGzhQrCodeTicketRep getWxGzhQrCode(Long sharedId, Integer dsType, Long popularizeId, String loginPhone, String loginEmail, String dsCode) throws Exception;
 
     /**
      * 获取公众号带参数的永久二维码

+ 3 - 2
netflix-service/src/main/java/com/cyksj/service/wechat/impl/WeChatServiceImpl.java

@@ -483,7 +483,7 @@ public class WeChatServiceImpl implements WeChatService {
     }
 
     @Override
-    public WxGzhQrCodeTicketRep getWxGzhQrCode(Long sharedId, Integer dsType, Long popularizeId, String loginPhone, String dsCode) throws Exception {
+    public WxGzhQrCodeTicketRep getWxGzhQrCode(Long sharedId, Integer dsType, Long popularizeId, String loginPhone, String loginEmail, String dsCode) throws Exception {
         SysConfig sysConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class)
                 .eq(SysConfig::getSysKey, Constant.QR_CODE_WX_APP_ID).last("limit 1"));
         String appid = null;
@@ -497,7 +497,7 @@ public class WeChatServiceImpl implements WeChatService {
         //scene_str:场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
         String scene_str = RandomUtil.randomString(16);
         int expireTime = 60;
-        if (StrUtil.isNotBlank(loginPhone)) {
+        if (StrUtil.isNotBlank(loginPhone) || StrUtil.isNotBlank(loginEmail)) {
             expireTime = 25;
         }
         DateTime dateTime = DateUtil.offsetSecond(DateTime.now(), expireTime);
@@ -519,6 +519,7 @@ public class WeChatServiceImpl implements WeChatService {
                     .setPopularizeId(popularizeId)
                     .setDsType(dsType)
                     .setLoginPhone(loginPhone)
+                    .setLoginEmail(loginEmail)
                     .setDsCode(dsCode);
             String state = Codec.DoBase64.custom().setData(Jsons.toJson(gzhBodyDto)).encodeAsText();
             redisService.set(RedisService.key.WX_GZH_QRCODE_SHARED_LOGIN.getNameFormat(scene_str), state, RedisService.key.WX_GZH_QRCODE_SHARED_LOGIN.getTimeout());

+ 8 - 5
netflix-web/src/main/java/com/cyksj/web/controller/group/GroupRelationController.java

@@ -35,6 +35,7 @@ import com.cyksj.service.mange.coupon.CouponCommonService;
 import com.cyksj.service.mange.ticket.TicketAdvertiseConfigClickRecordService;
 import com.cyksj.service.order.OrderDonService;
 import com.cyksj.service.relation.GroupRelationFrontService;
+import com.cyksj.service.user.UserBindRelationService;
 import com.cyksj.service.user.UserService;
 import com.cyksj.web.util.StpUserUtil;
 import com.ejlchina.searcher.BeanSearcher;
@@ -70,6 +71,8 @@ public class GroupRelationController {
 
     private final UserService userService;
 
+    private final UserBindRelationService userBindRelationService;
+
     private final ChatGptPwdViewRecordMapper chatGptPwdViewRecordMapper;
 
     private final HttpServletRequest request;
@@ -119,7 +122,7 @@ public class GroupRelationController {
     @PutMapping("/update/set/account")
     public Result<String> setAccount(@RequestBody GroupsRelation relation) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<Long> userIds = userService.getRelationUserIdList(userId, null);
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
         GroupsRelation re = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
                 .eq(GroupsRelation::getId, relation.getId())
                 .in(GroupsRelation::getUserId, userIds)
@@ -162,7 +165,7 @@ public class GroupRelationController {
     @GetMapping("/get")
     public Result<List<UserTicketView>> getUserTicketView() {
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<Long> userIds = userService.getRelationUserIdList(userId, null);
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
         List<UserTicketView> ticketViews = beanSearcher.searchAll(UserTicketView.class, MapUtils.builder()
                 .field(UserTicketView::getUserId, userIds).op(Operator.InList)
                 .field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList)
@@ -177,7 +180,7 @@ public class GroupRelationController {
     @GetMapping("/recordView/{relationId}")
     public Result<String> recordGPTPwdView(@PathVariable Long relationId) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<Long> userIds = userService.getRelationUserIdList(userId, null);
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
         GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
                 .field(GroupsRelationView::getUserId, userIds).op(Operator.InList)
                 .field(GroupsRelationView::getId, relationId).build());
@@ -226,7 +229,7 @@ public class GroupRelationController {
     @GetMapping("/get/authCode")
     public Result<String> getAuthCode(Long relationId) {
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<Long> userIds = userService.getRelationUserIdList(userId, null);
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
         //每个人 每月只能获取3次
         if (relationId == null) throw BusinessRuntimeException.getInstance("车票不存在");
         GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
@@ -486,7 +489,7 @@ public class GroupRelationController {
     public Result<Page<UserRecommendGoodsFrontView>> getRecommendGoodsViews(@RequestParam(defaultValue = "0") Integer start, @RequestParam(defaultValue = "5") Integer limit) {
         //推荐用户未购买的车票平台 优先展示ai类平台 然后是影视流媒体
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<Long> userIds = userService.getRelationUserIdList(userId, null);
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
         List<Long> filter_goods_id = relationMapper.getTicketGoodsId(userIds, List.of("validity", "overdue", "outside"));
         //用户是否购买过奈飞产品
         Boolean isPayNf = false;

+ 37 - 47
netflix-web/src/main/java/com/cyksj/web/controller/market/TaskFrontController.java

@@ -1,17 +1,14 @@
 package com.cyksj.web.controller.market;
 
-import cn.hutool.core.lang.Validator;
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.annotation.NoSubmit;
-import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.mapper.market.task.UserBindDetailMapper;
+import com.cyksj.mapper.UserMapper;
 import com.cyksj.model.entity.TaskFollowPlatVerify;
-import com.cyksj.model.entity.UserBindDetail;
+import com.cyksj.model.entity.User;
 import com.cyksj.model.request.LoginReq;
 import com.cyksj.model.request.TaskFollowReq;
+import com.cyksj.model.request.UserBindInfoReq;
 import com.cyksj.model.views.TaskFrontView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.market.MarketFrontService;
@@ -21,12 +18,10 @@ import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
-import org.springframework.dao.DuplicateKeyException;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.Optional;
 
 /*
  *项目名: netflix
@@ -43,14 +38,12 @@ public class TaskFrontController {
 
 	private final MarketFrontService marketFrontService;
 
-	private final HttpServletRequest request;
+	private final UserMapper userMapper;
 
-	private final UserBindDetailMapper UserBindDetailMapper;
+	private final BindTaskService bindTaskService;
 
 	private final RedisService redisService;
 
-	private final BindTaskService bindTaskService;
-
 	/**
 	 * 任务列表
 	 */
@@ -80,9 +73,11 @@ public class TaskFrontController {
 	 */
 	@PostMapping("/bind/phone")
 	@NoSubmit
+	@Deprecated
 	public Result<String> bindPhone(@RequestBody LoginReq phoneReq) {
 		Long userId = StpUserUtil.getLoginIdAsLong();
-		bindTaskService.bindPhone(userId, phoneReq.getPhone(), phoneReq.getCode(), true);
+		User user = userMapper.selectById(userId);
+		bindTaskService.bindPhone(user, phoneReq.getPhone(), phoneReq.getCode());
 		return GatewayResponse.SUCCESS.newBuilder().toResult("绑定手机号成功");
 	}
 
@@ -90,54 +85,49 @@ public class TaskFrontController {
 	 * 绑定邮箱
 	 */
 	@PostMapping("/bind/email")
+	@Deprecated
 	public Result<String> bindEmail(@RequestBody LoginReq phoneReq) {
 		Long userId = StpUserUtil.getLoginIdAsLong();
-		if (!Validator.isEmail(phoneReq.getEmail())) {
-			throw BusinessRuntimeException.getInstance("请输入正确的邮箱");
-		}
-		UserBindDetail other = UserBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
-				.eq(UserBindDetail::getEmail, phoneReq.getEmail()).ne(UserBindDetail::getUserId, userId).select(UserBindDetail::getId).last("limit 1"));
-		if (other != null) {
-			throw BusinessRuntimeException.getInstance("该邮箱已被绑定");
-		}
-		UserBindDetail bindPhone = Optional.ofNullable(UserBindDetailMapper.selectOne(Wrappers.lambdaQuery(UserBindDetail.class)
-				.eq(UserBindDetail::getUserId, userId).last("limit 1"))).orElse(new UserBindDetail());
-		if (StrUtil.isNotBlank(bindPhone.getEmail())) {
-			throw BusinessRuntimeException.getInstance("您已绑定邮箱");
-		}
-		String code = redisService.getStr(RedisService.key.EMAIL_CODE_KEY.getNameFormat(phoneReq.getEmail()));
-		if (StrUtil.isEmpty(code)) {
-			throw BusinessRuntimeException.getInstance("邮箱验证码已失效,请重新获取");
-		}
-		if (!StrUtil.equals(phoneReq.getCode(), code)) {
-			throw BusinessRuntimeException.getInstance("邮箱验证码错误,请重新输入");
-		}
-		bindPhone.setEmail(phoneReq.getEmail());
-		bindPhone.setUserId(userId);
-		try {
-			if (bindPhone.getId() == null) {
-				UserBindDetailMapper.insert(bindPhone);
-			}else {
-				UserBindDetailMapper.updateById(bindPhone);
-			}
-		} catch (DuplicateKeyException e) {
-
-		}
-		redisService.del(RedisService.key.EMAIL_CODE_KEY.getNameFormat(phoneReq.getEmail()));
+		User user = userMapper.selectById(userId);
+		bindTaskService.bindEmail(user, phoneReq.getEmail(), phoneReq.getCode());
 		return GatewayResponse.SUCCESS.newBuilder().toResult("绑定邮箱成功");
 	}
 
-
 	/**
 	 * 修改手机号
 	 */
 	@PutMapping("/put/bind/phone")
+	@Deprecated
 	public Result<String> updateBindPhone(@RequestBody LoginReq phoneReq) {
 		Long userId = StpUserUtil.getLoginIdAsLong();
-		bindTaskService.updateBindPhone(userId, phoneReq.getPhone(), phoneReq.getCode());
+		User user = userMapper.selectById(userId);
+		bindTaskService.updateBindPhone(user, phoneReq.getPhone(), phoneReq.getCode());
 		return GatewayResponse.SUCCESS.newBuilder().toResult("更换手机号成功");
 	}
 
+	/**
+	 * 绑定手机号、邮箱、微信
+	 */
+	@PostMapping("/bind/account")
+	@NoSubmit
+	public Result<Object> bindOtherAccount(@RequestBody @Validated UserBindInfoReq request) throws Exception {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		request.setUserId(userId);
+		return bindTaskService.bindOtherAccount(request);
+	}
+
+	/**
+	 * 修改绑定信息
+	 */
+	@PutMapping("/put/bind/account")
+	@NoSubmit
+	public Result<String> updateBindAccount(@RequestBody @Validated UserBindInfoReq request) {
+		Long userId = StpUserUtil.getLoginIdAsLong();
+		request.setUserId(userId);
+		bindTaskService.updateBindAccount(request);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
 	/**
 	 * 去完成关注任务
 	 */

+ 3 - 3
netflix-web/src/main/java/com/cyksj/web/controller/payment/OrderController.java

@@ -35,7 +35,7 @@ import com.cyksj.service.paypal.PayPalService;
 import com.cyksj.service.paypal.PaypalPayConfigService;
 import com.cyksj.service.stripe.StripePayConfigService;
 import com.cyksj.service.stripe.StripeService;
-import com.cyksj.service.user.UserService;
+import com.cyksj.service.user.UserBindRelationService;
 import com.cyksj.web.util.StpUserUtil;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
@@ -103,7 +103,7 @@ public class OrderController {
     private OrderDonWaybillMapper waybillMapper;
 
     @Autowired
-    private UserService userService;
+    private UserBindRelationService UserBindRelationService;
 
     @Autowired
     private PaypalPayConfigService paypalPayConfigService;
@@ -341,7 +341,7 @@ public class OrderController {
     @GetMapping("/get")
     public Result<SearchResult<OrderDonView>> list(){
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<Long> userIds = userService.getRelationUserIdList(userId, null);
+        List<Long> userIds = UserBindRelationService.getRelationUserIdList(userId, null);
         SearchResult<OrderDonView> search = beanSearcher.search(OrderDonView.class, MapUtils.flatBuilder(request.getParameterMap())
                 .field(OrderDonView::getUserId, userIds).op(Operator.InList)
                 .orderBy(OrderDonView::getId).desc()

+ 16 - 13
netflix-web/src/main/java/com/cyksj/web/controller/user/AuthorizationController.java

@@ -15,16 +15,17 @@ import com.cyksj.config.wxlogin.WxOpenPlatYHLXLoginConfig;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.PhoneCodeMapper;
-import com.cyksj.mapper.manage.cps.UserDistributePopularizeMapper;
-import com.cyksj.model.dto.*;
+import com.cyksj.model.dto.AuthRedirect;
+import com.cyksj.model.dto.AuthToken;
+import com.cyksj.model.dto.GzhOAuth2UserInfo;
+import com.cyksj.model.dto.JsSdkTicket;
 import com.cyksj.model.entity.PhoneCode;
 import com.cyksj.model.entity.User;
 import com.cyksj.model.request.LoginReq;
-import com.cyksj.model.response.LoginPhoneRep;
+import com.cyksj.model.response.UserAuthLoginResp;
 import com.cyksj.model.response.WxGzhQrCodeTicketRep;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.authorization.AuthorizationService;
-import com.cyksj.service.distribute.DistributeService;
 import com.cyksj.service.mail.MailService;
 import com.cyksj.service.template.TemplateCommonService;
 import com.cyksj.service.user.BadIntentionOpService;
@@ -234,7 +235,7 @@ public class AuthorizationController {
     @GetMapping("/wx/gzh/login/qrCode")
     public Result<WxGzhQrCodeTicketRep> getWxGzhQrCode(Long sharedId, Integer dsType, Long popularizeId, String dsCode) throws Exception {
         //获取gzh带参数的二维码
-        WxGzhQrCodeTicketRep result = weChatService.getWxGzhQrCode(sharedId, dsType, popularizeId, null, dsCode);
+        WxGzhQrCodeTicketRep result = weChatService.getWxGzhQrCode(sharedId, dsType, popularizeId, null, null, dsCode);
         return GatewayResponse.SUCCESS.newBuilder().toResult(result);
     }
 
@@ -243,7 +244,7 @@ public class AuthorizationController {
      */
     @GetMapping("/wx/gzh/qrCode")
     public Result<WxGzhQrCodeTicketRep> getWxGzhBindQrcode(String loginPhone) throws Exception {
-        WxGzhQrCodeTicketRep result = weChatService.getWxGzhQrCode(null, null, null, loginPhone, null);
+        WxGzhQrCodeTicketRep result = weChatService.getWxGzhQrCode(null, null, null, loginPhone, null, null);
         return GatewayResponse.SUCCESS.newBuilder().toResult(result);
     }
 
@@ -364,11 +365,13 @@ public class AuthorizationController {
         if (email == null || !Validator.isEmail(email)) {
             throw BusinessRuntimeException.getInstance("请输入正确邮箱");
         }
-        //首次注册只能gmail邮箱
-        if (!email.contains("@gmail")) {
-            User user = userService.getOne(Wrappers.lambdaQuery(User.class).eq(User::getEmail, email).last("limit 1"));
-            if (user == null) {
-                throw BusinessRuntimeException.getInstance("暂只支持使用谷歌邮箱注册");
+        if (envCommonService.isPrdEnv()) {
+            //首次注册只能gmail邮箱
+            if (!email.contains("@gmail")) {
+                User user = userService.getOne(Wrappers.lambdaQuery(User.class).eq(User::getEmail, email).last("limit 1"));
+                if (user == null) {
+                    throw BusinessRuntimeException.getInstance("暂只支持使用谷歌邮箱注册");
+                }
             }
         }
         String code = mailService.sendLoginCodeEmailToPeople(digit, email);
@@ -383,11 +386,11 @@ public class AuthorizationController {
      */
     @PostMapping("/login/phone")
     @NoSubmit
-    public Result<LoginPhoneRep> loginByPhone(@RequestBody LoginReq loginReq) throws Exception {
+    public Result<UserAuthLoginResp> loginByPhone(@RequestBody LoginReq loginReq) throws Exception {
         User user = userService.webLogin(loginReq);
         //写回登陆信息
         StpUserUtil.login(user.getId());
-        LoginPhoneRep loginPhoneRep = new LoginPhoneRep(StpUserUtil.getTokenValue(), user.getShowId(), user.getNickname(), user.getHeadimgurl());
+        UserAuthLoginResp loginPhoneRep = new UserAuthLoginResp(StpUserUtil.getTokenValue(), user.getShowId(), user.getNickname(), user.getHeadimgurl());
         if (loginReq.getPhone() != null) {
             redisService.del(RedisService.key.PHONE_CODE_KEY.getName() + loginReq.getPhone());
         }

+ 45 - 7
netflix-web/src/main/java/com/cyksj/web/controller/user/UserController.java

@@ -9,7 +9,6 @@ import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayApiCode;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.OrderDonMapper;
-import com.cyksj.mapper.RegisterOrderDonMapper;
 import com.cyksj.mapper.manage.coupon.CouponUserMapper;
 import com.cyksj.model.dto.UserWhoami;
 import com.cyksj.model.entity.*;
@@ -18,11 +17,12 @@ import com.cyksj.model.request.ExchangeCodeTicket;
 import com.cyksj.model.request.ReceiveBenefitsReq;
 import com.cyksj.model.request.UserReq;
 import com.cyksj.model.request.WorkOrderReq;
+import com.cyksj.model.response.UserAuthLoginResp;
 import com.cyksj.model.views.*;
 import com.cyksj.service.corp.CropChatService;
 import com.cyksj.service.exchange.ExchangeCodeService;
 import com.cyksj.service.order.UserRealOrderBenefitsService;
-import com.cyksj.service.relation.GroupRelationFrontService;
+import com.cyksj.service.user.UserBindRelationService;
 import com.cyksj.service.user.UserService;
 import com.cyksj.service.user.WorkOrderFrontService;
 import com.cyksj.web.util.StpUserUtil;
@@ -52,8 +52,6 @@ public class UserController {
 
     private final ExchangeCodeService exchangeCodeService;
 
-    private final GroupRelationFrontService groupRelationFrontService;
-
     private final CouponUserMapper couponUserMapper;
 
     private final OrderDonMapper orderDonMapper;
@@ -64,12 +62,12 @@ public class UserController {
 
     private final WorkOrderFrontService workOrderFrontService;
 
-    private final RegisterOrderDonMapper registerOrderDonMapper;
-
     private final HttpServletRequest request;
 
     private final CropChatService cropChatService;
 
+    private final UserBindRelationService userBindRelationService;
+
     @GetMapping(value = "/wx/whoami")
     public Result<UserWhoami> whoami() {
         long userId = StpUserUtil.getLoginIdAsLong();
@@ -94,7 +92,7 @@ public class UserController {
     @GetMapping("/personal")
     public Result<UserPersonalView> getPersonalView() {
         long userId = StpUserUtil.getLoginIdAsLong();
-        List<Long> userIds = userService.getRelationUserIdList(userId, null);
+        List<Long> userIds = userBindRelationService.getRelationUserIdList(userId, null);
         Number ticketNum = beanSearcher.searchCount(UserTicketView.class, MapUtils.builder()
                 .field(UserTicketView::getUserId, userIds).op(Operator.InList)
                 .field(RenewalView::getStatus, List.of("validity", "overdue", "outside")).op(Operator.InList)
@@ -300,4 +298,44 @@ public class UserController {
         String qrCode = cropChatService.getCorpServiceCode(goodsId);
         return GatewayResponse.SUCCESS.newBuilder().toResult(qrCode);
     }
+
+    /**
+     * 用户账号关联列表
+     */
+    @GetMapping("/get/userAccounts")
+    public Result<List<UserBindAccountView>> getUserBindAccountViews() {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        List<Long> relationUserIdList = userBindRelationService.getRelationUserIdList(userId, null);
+        List<UserBindAccountView> accountViews = beanSearcher.searchAll(UserBindAccountView.class, MapUtils.builder().field(UserBindAccountView::getUserId, relationUserIdList)
+                .op(Operator.InList)
+                .build());
+        if (relationUserIdList.size() > 1) {
+            for (UserBindAccountView accountView : accountViews) {
+                if (accountView.getUserId().equals(userId)) {
+                    accountViews.remove(accountView);
+                    accountViews.add(0, accountView);
+                    break;
+                }
+            }
+        }
+        return GatewayResponse.SUCCESS.newBuilder().toResult(accountViews);
+    }
+
+    /**
+     * 切换账号
+     */
+    @PutMapping("/switch/account")
+    public Result<UserAuthLoginResp> switchOtherAccount(@RequestBody UserBindAccountView request) {
+        long userId = StpUserUtil.getLoginIdAsLong();
+        Long switchUserId = request.getUserId();
+        List<Long> relationUserIdList = userBindRelationService.getRelationUserIdList(userId, null);
+        if (!relationUserIdList.contains(switchUserId)) {
+            throw BusinessRuntimeException.getInstance("切换账号异常,请刷新页面重试");
+        }
+        User switch_user = userService.getById(switchUserId);
+        Assert.notNull(switch_user, "切换的账号不存在");
+        StpUserUtil.login(switch_user.getId());
+        UserAuthLoginResp loginPhoneRep = new UserAuthLoginResp(StpUserUtil.getTokenValue(), switch_user.getShowId(), switch_user.getNickname(), switch_user.getHeadimgurl());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(loginPhoneRep);
+    }
 }