From ddf7b9fbc7cc9f992db14eac2bc168152f9c6299 Mon Sep 17 00:00:00 2001 From: wx-jincw Date: Sat, 23 May 2026 14:53:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BE=AE=E4=BF=A1=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/public.js | 9 ++ app/config/app.js | 9 +- app/manifest.json | 4 +- .../com/zbkj/common/constants/Constants.java | 2 + .../request/WxBindingAccountRequest.java | 40 +++++++++ .../front/controller/WeChatController.java | 13 +++ .../zbkj/front/service/UserCenterService.java | 13 +++ .../service/impl/UserCenterServiceImpl.java | 83 +++++++++++++++++++ 8 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 crmeb/crmeb-common/src/main/java/com/zbkj/common/request/WxBindingAccountRequest.java diff --git a/app/api/public.js b/app/api/public.js index 91144d0..ab3cc6c 100644 --- a/app/api/public.js +++ b/app/api/public.js @@ -90,6 +90,15 @@ export function getUserPhone(data){ return request.post('wechat/register/binding/phone',data,{noAuth : true}); } +/** + * 小程序微信绑定已有账号(账号+密码) + * 关闭强制获取手机号时使用,将微信 openId 关联到已有账号 + * @param {Object} data { account, password, key } + */ +export function bindRoutineAccount(data) { + return request.post('wechat/register/binding/account', data, { noAuth: true }); +} + /** * APP微信登录 * @param {Object} data diff --git a/app/config/app.js b/app/config/app.js index eadf9eb..6c1f665 100644 --- a/app/config/app.js +++ b/app/config/app.js @@ -38,5 +38,12 @@ module.exports = { // 缓存时间 0 永久 EXPIRE:0, //分页最多显示条数 - LIMIT: 10 + LIMIT: 10, + /** + * 小程序微信登录:新用户是否强制获取手机号 + * true=开启(弹出微信手机号授权,走 register/binding/phone) + * false=关闭(跳转账号密码页,走 register/binding/account 绑定已有账号) + * 可被后端 wechat/getLogo 返回的 routineLoginRequirePhone 覆盖 + */ + MP_WECHAT_REQUIRE_PHONE: true }; diff --git a/app/manifest.json b/app/manifest.json index 6e796ed..b1c5a4e 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -2,8 +2,8 @@ "name" : "八方物业", "appid" : "__UNI__B905528", "description" : "八方物业", - "versionName" : "1.0.2", - "versionCode" : 1002, + "versionName" : "1.0.3", + "versionCode" : 1003, "transformPx" : false, /* 5+App特有相关 */ "app-plus" : { diff --git a/crmeb/crmeb-common/src/main/java/com/zbkj/common/constants/Constants.java b/crmeb/crmeb-common/src/main/java/com/zbkj/common/constants/Constants.java index 1e15f3a..9308c8c 100644 --- a/crmeb/crmeb-common/src/main/java/com/zbkj/common/constants/Constants.java +++ b/crmeb/crmeb-common/src/main/java/com/zbkj/common/constants/Constants.java @@ -162,6 +162,8 @@ public class Constants { public static final String CONFIG_KEY_FRONT_API_URL = "front_api_url"; //移动商城接口地址 public static final String CONFIG_KEY_SITE_LOGO = "mobile_top_logo"; //logo地址 public static final String CONFIG_KEY_MOBILE_LOGIN_LOGO = "mobile_login_logo"; // 移动端登录 logo + /** 小程序微信登录是否强制获取手机号:1=开启(默认),0=关闭(走账号密码绑定微信) */ + public static final String CONFIG_KEY_ROUTINE_LOGIN_REQUIRE_PHONE = "routine_login_require_phone"; public static final String CONFIG_KEY_SITE_NAME = "site_name"; //网站名称 public static final String CONFIG_SITE_TENG_XUN_MAP_KEY = "tengxun_map_key"; //腾讯地图key public static final String CONFIG_BANK_LIST = "user_extract_bank"; //可提现银行 diff --git a/crmeb/crmeb-common/src/main/java/com/zbkj/common/request/WxBindingAccountRequest.java b/crmeb/crmeb-common/src/main/java/com/zbkj/common/request/WxBindingAccountRequest.java new file mode 100644 index 0000000..40058db --- /dev/null +++ b/crmeb/crmeb-common/src/main/java/com/zbkj/common/request/WxBindingAccountRequest.java @@ -0,0 +1,40 @@ +package com.zbkj.common.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.zbkj.common.constants.RegularConstants; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; +import java.io.Serializable; + +/** + * 小程序微信绑定已有账号请求对象 + * 用于关闭「强制获取手机号」时,通过账号密码将微信 openId 关联到已有用户 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@ApiModel(value = "WxBindingAccountRequest", description = "小程序微信绑定已有账号请求对象") +public class WxBindingAccountRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "账号(手机号)", required = true) + @NotBlank(message = "账号不能为空") + @Pattern(regexp = RegularConstants.PHONE_TWO, message = "请输入正确的手机号") + @JsonProperty("account") + private String account; + + @ApiModelProperty(value = "密码", required = true) + @NotBlank(message = "密码不能为空") + private String password; + + @ApiModelProperty(value = "微信授权 register 阶段返回的 key", required = true) + @NotBlank(message = "key不能为空") + private String key; +} diff --git a/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java b/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java index bdf5371..3e0863e 100644 --- a/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java +++ b/crmeb/crmeb-front/src/main/java/com/zbkj/front/controller/WeChatController.java @@ -3,6 +3,7 @@ package com.zbkj.front.controller; import com.zbkj.common.model.wechat.TemplateMessage; import com.zbkj.common.request.RegisterAppWxRequest; import com.zbkj.common.request.RegisterThirdUserRequest; +import com.zbkj.common.request.WxBindingAccountRequest; import com.zbkj.common.request.WxBindingPhoneRequest; import com.zbkj.common.response.CommonResult; import com.zbkj.common.response.LoginResponse; @@ -87,6 +88,16 @@ public class WeChatController { return CommonResult.success(userCenterService.registerBindingPhone(request)); } + /** + * 小程序微信绑定已有账号(账号+密码) + * 关闭 routine_login_require_phone 后,新微信用户通过此接口关联已有账号 + */ + @ApiOperation(value = "小程序微信绑定已有账号") + @RequestMapping(value = "/register/binding/account", method = RequestMethod.POST) + public CommonResult registerBindingAccount(@RequestBody @Validated WxBindingAccountRequest request){ + return CommonResult.success(userCenterService.registerBindingAccount(request)); + } + /** * 获取微信公众号js配置 */ @@ -105,6 +116,8 @@ public class WeChatController { public CommonResult> getLogo(){ Map map = new HashMap<>(); map.put("logoUrl", userCenterService.getLogo()); + // 1=微信登录新用户强制获取手机号,0=跳转账号密码绑定微信 + map.put("routineLoginRequirePhone", userCenterService.getRoutineLoginRequirePhone()); return CommonResult.success(map); } diff --git a/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/UserCenterService.java b/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/UserCenterService.java index 559bd37..b89b2c7 100644 --- a/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/UserCenterService.java +++ b/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/UserCenterService.java @@ -173,6 +173,19 @@ public interface UserCenterService extends IService { */ LoginResponse registerBindingPhone(WxBindingPhoneRequest request); + /** + * 小程序微信绑定已有账号(账号+密码) + * @param request 请求参数 + * @return 登录信息 + */ + LoginResponse registerBindingAccount(WxBindingAccountRequest request); + + /** + * 小程序微信登录是否强制获取手机号 + * @return 1=开启,0=关闭 + */ + String getRoutineLoginRequirePhone(); + /** * 用户积分记录列表 * @param pageParamRequest 分页参数 diff --git a/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/impl/UserCenterServiceImpl.java b/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/impl/UserCenterServiceImpl.java index 0cb8fca..9b2449e 100644 --- a/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/impl/UserCenterServiceImpl.java +++ b/crmeb/crmeb-front/src/main/java/com/zbkj/front/service/impl/UserCenterServiceImpl.java @@ -489,6 +489,16 @@ public class UserCenterServiceImpl extends ServiceImpl implements return systemConfigService.getValueByKey(Constants.CONFIG_KEY_MOBILE_LOGIN_LOGO); } + /** + * 小程序微信登录是否强制获取手机号 + * 系统配置 routine_login_require_phone:1=开启(默认),0=关闭(走账号密码绑定) + */ + @Override + public String getRoutineLoginRequirePhone() { + String value = systemConfigService.getValueByKey(Constants.CONFIG_KEY_ROUTINE_LOGIN_REQUIRE_PHONE); + return StrUtil.isBlank(value) ? "1" : value; + } + /** * 小程序登录 * @param code String 前端临时授权code @@ -854,6 +864,79 @@ public class UserCenterServiceImpl extends ServiceImpl implements return loginResponse; } + /** + * 小程序微信绑定已有账号(账号+密码) + * 关闭「强制获取手机号」时,新微信用户通过已有账号完成关联,下次可直接微信登录 + */ + @Override + public LoginResponse registerBindingAccount(WxBindingAccountRequest request) { + Object cache = redisUtil.get(request.getKey()); + if (ObjectUtil.isNull(cache)) { + throw new CrmebException("微信授权已过期,请重新点击微信登录"); + } + RegisterThirdUserRequest registerThirdUserRequest = JSONObject.parseObject(cache.toString(), RegisterThirdUserRequest.class); + if (!Constants.USER_LOGIN_TYPE_PROGRAM.equals(registerThirdUserRequest.getType())) { + throw new CrmebException("仅支持小程序微信绑定"); + } + + User user = userService.getByPhone(request.getAccount()); + if (ObjectUtil.isNull(user)) { + throw new CrmebException("此账号未注册"); + } + if (!user.getStatus()) { + throw new CrmebException("此账号被禁用"); + } + + String encryptedPassword = CrmebUtil.encryptPassword(request.getPassword(), request.getAccount()); + if (!user.getPwd().equals(encryptedPassword)) { + throw new CrmebException("密码错误"); + } + + UserToken boundByUser = userTokenService.getTokenByUserId(user.getUid(), Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM); + if (ObjectUtil.isNotNull(boundByUser)) { + throw new CrmebException("该账号已绑定微信小程序"); + } + + UserToken boundByOpenId = userTokenService.getByOpenidAndType( + registerThirdUserRequest.getOpenId(), Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM); + if (ObjectUtil.isNotNull(boundByOpenId)) { + throw new CrmebException("该微信已绑定其他账号"); + } + + User finalUser = user; + Boolean execute = transactionTemplate.execute(e -> { + userTokenService.bind( + registerThirdUserRequest.getOpenId(), + Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM, + finalUser.getUid()); + return Boolean.TRUE; + }); + if (!execute) { + throw new CrmebException("绑定微信失败,请稍后重试"); + } + + if (ObjectUtil.isNotNull(registerThirdUserRequest.getSpreadPid()) && registerThirdUserRequest.getSpreadPid() > 0) { + loginService.bindSpread(user, registerThirdUserRequest.getSpreadPid()); + } + + user.setLastLoginTime(DateUtil.nowDateTime()); + userService.updateById(user); + redisUtil.delete(request.getKey()); + + LoginResponse loginResponse = new LoginResponse(); + try { + loginResponse.setToken(tokenComponent.createToken(user)); + } catch (Exception e) { + logger.error(StrUtil.format("绑定微信账号后生成token失败,uid={}", user.getUid())); + e.printStackTrace(); + } + loginResponse.setType("login"); + loginResponse.setUid(user.getUid()); + loginResponse.setNikeName(user.getNickname()); + loginResponse.setPhone(user.getPhone()); + return loginResponse; + } + /** * 用户积分记录列表 * @param pageParamRequest 分页参数