|
|
@@ -1,17 +1,24 @@
|
|
|
package com.fs.app.controller;
|
|
|
|
|
|
+import cn.binarywang.wx.miniapp.api.WxMaService;
|
|
|
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
|
|
+import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
|
|
import cn.hutool.core.date.DateTime;
|
|
|
+import com.fs.app.annotation.Login;
|
|
|
import com.fs.app.annotation.UserOperationLog;
|
|
|
+import com.fs.app.enums.ErrorCode;
|
|
|
import com.fs.app.param.FsUserLoginByMpParam;
|
|
|
import com.fs.app.utils.JwtUtils;
|
|
|
import com.fs.common.core.domain.R;
|
|
|
import com.fs.common.core.redis.RedisCache;
|
|
|
+import com.fs.core.config.WxMaConfiguration;
|
|
|
import com.fs.course.mapper.FsCourseSopLogsMapper;
|
|
|
import com.fs.course.mapper.FsCourseWatchLogMapper;
|
|
|
import com.fs.his.domain.FsUser;
|
|
|
import com.fs.his.enums.FsUserOperationEnum;
|
|
|
import com.fs.his.service.IFsUserService;
|
|
|
import com.fs.his.utils.ConfigUtil;
|
|
|
+import com.fs.his.utils.PhoneUtil;
|
|
|
import com.fs.qw.mapper.QwExternalContactMapper;
|
|
|
import com.fs.sop.params.QwSopSettingTimeParam;
|
|
|
import com.fs.system.mapper.SysConfigMapper;
|
|
|
@@ -20,6 +27,7 @@ import com.fs.wx.mp.WxMessageType;
|
|
|
import com.fs.wx.mp.WxServiceMsgDto;
|
|
|
import io.swagger.annotations.ApiOperation;
|
|
|
import lombok.Synchronized;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
|
|
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
|
|
|
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
|
|
@@ -43,10 +51,10 @@ import java.util.*;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
-
|
|
|
+@Slf4j
|
|
|
@RestController
|
|
|
@RequestMapping("/app/wx/mp")
|
|
|
-public class WxMpController {
|
|
|
+public class WxMpController extends AppBaseController {
|
|
|
Logger logger= LoggerFactory.getLogger(getClass());
|
|
|
@Autowired
|
|
|
private WxMpService wxMpService;
|
|
|
@@ -154,6 +162,138 @@ public class WxMpController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Login
|
|
|
+ @ApiOperation("绑定手机号")
|
|
|
+ @PostMapping("/setIPhoneNumber")
|
|
|
+ public R setIPhoneNumber(@RequestBody FsUserLoginByMpParam param) {
|
|
|
+ log.info("=====================进入小程序授权登录, 入参: {}", param);
|
|
|
+
|
|
|
+ // 参数校验
|
|
|
+ if (StringUtils.isBlank(param.getCode())) {
|
|
|
+ log.warn("绑定手机号失败:code参数为空");
|
|
|
+ return R.error(ErrorCode.PARAM_EMPTY.getCode(), "授权码不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(param.getAppId())) {
|
|
|
+ log.warn("绑定手机号失败:appId参数为空");
|
|
|
+ return R.error(ErrorCode.PARAM_EMPTY.getCode(), "应用ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ WxMaService wxService = null;
|
|
|
+ try {
|
|
|
+ // 获取微信服务实例
|
|
|
+ wxService = WxMaConfiguration.getMaService(param.getAppId());
|
|
|
+ if (wxService == null) {
|
|
|
+ log.error("绑定手机号失败:未找到对应的微信小程序服务,appId={}", param.getAppId());
|
|
|
+ return R.error(ErrorCode.WX_SERVICE_NOT_FOUND.getCode(), "微信服务初始化失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取session信息
|
|
|
+ WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(param.getCode());
|
|
|
+ if (session == null || StringUtils.isEmpty(session.getOpenid())) {
|
|
|
+ log.warn("绑定手机号失败:获取session信息异常,code={}", param.getCode());
|
|
|
+ return R.error(ErrorCode.WX_SESSION_FAILED.getCode(), "微信授权失败,请重新尝试");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解密手机号信息
|
|
|
+ WxMaPhoneNumberInfo phoneNoInfo = null;
|
|
|
+ try {
|
|
|
+ phoneNoInfo = wxService.getUserService().getPhoneNoInfo(
|
|
|
+ session.getSessionKey(),
|
|
|
+ param.getEncryptedData(),
|
|
|
+ param.getIv()
|
|
|
+ );
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("解密手机号失败:sessionKey={}, encryptedData={}, iv={}",
|
|
|
+ session.getSessionKey(), param.getEncryptedData(), param.getIv(), e);
|
|
|
+ return R.error(ErrorCode.WX_DECRYPT_FAILED.getCode(), "手机号解密失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (phoneNoInfo == null || StringUtils.isEmpty(phoneNoInfo.getPhoneNumber())) {
|
|
|
+ log.warn("绑定手机号失败:获取的手机号为空");
|
|
|
+ return R.error(ErrorCode.WX_PHONE_EMPTY.getCode(), "未获取到手机号信息");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前用户并更新手机号
|
|
|
+ String currentUserId = getUserId();
|
|
|
+ if (StringUtils.isBlank(currentUserId)) {
|
|
|
+ log.error("绑定手机号失败:用户ID获取失败");
|
|
|
+ return R.error(ErrorCode.USER_NOT_LOGIN.getCode(), "用户未登录");
|
|
|
+ }
|
|
|
+
|
|
|
+ Long userId;
|
|
|
+ try {
|
|
|
+ userId = Long.valueOf(currentUserId);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ log.error("绑定手机号失败:用户ID格式错误,userIdStr={}", currentUserId, e);
|
|
|
+ return R.error(ErrorCode.PARAM_FORMAT_ERROR.getCode(), "用户ID格式错误");
|
|
|
+ }
|
|
|
+
|
|
|
+ FsUser user = userService.selectFsUserByUserId(userId);
|
|
|
+ if (user == null) {
|
|
|
+ log.error("绑定手机号失败:用户不存在,userId={}", userId);
|
|
|
+ return R.error(ErrorCode.USER_NOT_EXIST.getCode(), "用户不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查手机号是否已被绑定
|
|
|
+ String phoneNumber = phoneNoInfo.getPhoneNumber();
|
|
|
+ if (StringUtils.isNotBlank(user.getPhone())) {
|
|
|
+ log.warn("绑定手机号失败:该用户已绑定手机号,userId={}, existingPhone={}", userId, user.getPhone());
|
|
|
+ return R.ok().put("code",ErrorCode.PHONE_ALREADY_BOUND.getCode()).put("msg", "该账号已绑定手机号").put("user",user);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查手机号是否已被其他用户绑定
|
|
|
+ FsUser existingUser = userService.selectFsUserByPhone(phoneNumber);
|
|
|
+ if (existingUser == null) {
|
|
|
+ existingUser = userService.selectFsUserByPhone(PhoneUtil.encryptPhone(phoneNumber));
|
|
|
+ }
|
|
|
+ if (existingUser != null && !existingUser.getUserId().equals(userId)) {
|
|
|
+ log.warn("绑定手机号失败:手机号已被其他用户绑定,phone={}, existingUserId={}",
|
|
|
+ phoneNumber, existingUser.getUserId());
|
|
|
+ return R.error(ErrorCode.PHONE_ALREADY_USED.getCode(), "该手机号已被其他账号绑定");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新用户手机号
|
|
|
+ user.setPhone(phoneNumber);
|
|
|
+ int updateResult = userService.updateFsUser(user);
|
|
|
+
|
|
|
+ if (updateResult <= 0) {
|
|
|
+ log.error("绑定手机号失败:数据库更新失败,userId={}, phone={}", userId, phoneNumber);
|
|
|
+ return R.error(ErrorCode.DB_UPDATE_FAILED.getCode(), "手机号绑定失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("绑定手机号成功:userId={}, phone={}", userId, phoneNumber);
|
|
|
+ return R.ok("手机号绑定成功").put("user", user);
|
|
|
+
|
|
|
+ } catch (WxErrorException e) {
|
|
|
+ log.error("微信服务调用异常:code={}, appId={}, error={}",
|
|
|
+ param.getCode(), param.getAppId(), e.getMessage(), e);
|
|
|
+
|
|
|
+ // 根据微信错误码返回具体提示
|
|
|
+ int wxErrorCode = e.getError().getErrorCode();
|
|
|
+ String errorMsg = getWxErrorMsg(wxErrorCode);
|
|
|
+ return R.error(ErrorCode.WX_API_ERROR.getCode(), errorMsg);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("绑定手机号系统异常:param={}", param, e);
|
|
|
+ return R.error(ErrorCode.SYSTEM_ERROR.getCode(), "系统繁忙,请稍后再试");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据微信错误码获取友好提示信息
|
|
|
+ */
|
|
|
+ private String getWxErrorMsg(int wxErrorCode) {
|
|
|
+ switch (wxErrorCode) {
|
|
|
+ case 40029: return "授权码无效或已过期";
|
|
|
+ case 45011: return "操作频率限制,请稍后再试";
|
|
|
+ case 40013: return "无效的AppID";
|
|
|
+ case 40125: return "无效的AppSecret";
|
|
|
+ case 41008: return "缺少code参数";
|
|
|
+ default: return "微信服务异常,请稍后再试";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
|
|
|
private Date setSendTime(QwSopSettingTimeParam params) {
|
|
|
@@ -196,8 +336,4 @@ public class WxMpController {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
}
|