From 25df88d0ab9d7444ed1d162b9efa1259ac2f6f66 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期一, 27 四月 2026 10:13:53 +0800
Subject: [PATCH] 小程序对接finish
---
backend/src/main/java/com/sinata/appointment/service/MiniAuthApplicationService.java | 214 +++++++++++++++++++++++++++++++++--------------------
1 files changed, 134 insertions(+), 80 deletions(-)
diff --git a/backend/src/main/java/com/sinata/appointment/service/MiniAuthApplicationService.java b/backend/src/main/java/com/sinata/appointment/service/MiniAuthApplicationService.java
index 256ea59..42d87ab 100644
--- a/backend/src/main/java/com/sinata/appointment/service/MiniAuthApplicationService.java
+++ b/backend/src/main/java/com/sinata/appointment/service/MiniAuthApplicationService.java
@@ -2,11 +2,11 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sinata.appointment.constants.BizErrorCode;
-import com.sinata.appointment.constants.MiniLoginIntent;
import com.sinata.appointment.constants.MiniUserType;
import com.sinata.appointment.constants.MpStaffConstants;
import com.sinata.appointment.config.MiniStpUtil;
import com.sinata.appointment.dto.MiniLoginResponse;
+import com.sinata.appointment.dto.MiniProfileUpdateRequest;
import com.sinata.appointment.dto.MiniWxLoginRequest;
import com.sinata.appointment.entity.MpUser;
import com.sinata.appointment.entity.SysDept;
@@ -28,8 +28,6 @@
@Service
public class MiniAuthApplicationService {
- private static final String H5_PHONE_OPEN_ID_PREFIX = "H5_PHONE_";
-
private final MpUserMapper mpUserMapper;
private final SysDeptMapper sysDeptMapper;
private final WechatMiniGateway wechatMiniGateway;
@@ -47,68 +45,24 @@
public MiniLoginResponse loginByWx(MiniWxLoginRequest req) {
WxCode2SessionResult session = wechatMiniGateway.code2Session(req.getWxCode());
String openId = session.getOpenId();
- String phoneRaw = wechatMiniGateway.getPhoneNumber(req.getPhoneCode());
- String phone = PhoneNormalize.mainland(phoneRaw);
MpUser user =
mpUserMapper.selectOne(
new LambdaQueryWrapper<MpUser>()
.eq(MpUser::getOpenId, openId)
.eq(MpUser::getDelFlag, 0));
-
- if (MiniLoginIntent.EMPLOYEE.equals(req.getLoginIntent())) {
- if (user == null) {
- user = tryBindPreRegisteredEmployee(openId, session.getUnionId(), phone, phoneRaw);
+ if (user == null) {
+ if (!StringUtils.hasText(req.getPhoneCode())) {
+ throw new BizException(BizErrorCode.MINI_PHONE_AUTH_REQUIRED, "请先授权手机号完成登录");
}
- if (user == null) {
- throw new BizException(BizErrorCode.MINI_STAFF_NOT_BOUND, "员工未登记,请联系管理员开通后再登录");
- }
- assertAccountEnabled(user);
- if (!MiniUserType.EMPLOYEE.equals(user.getUserType())) {
- throw new BizException(
- BizErrorCode.MINI_LOGIN_INTENT_MISMATCH, "当前微信为访客身份,请使用访客入口登录");
- }
- if (user.getDeptId() == null) {
- throw new BizException(BizErrorCode.MINI_STAFF_NOT_BOUND, "员工未分配部门");
- }
- assertPhoneMatchesStored(user, phone);
- syncMpUserMobile(user, phoneRaw);
- if (user.getUnionId() == null && session.getUnionId() != null) {
- user.setUnionId(session.getUnionId());
- mpUserMapper.updateById(user);
- }
- MiniStpUtil.login(user.getId());
- return buildResponse(user);
+ String phoneRaw = wechatMiniGateway.getPhoneNumber(req.getPhoneCode());
+ String phone = PhoneNormalize.mainland(phoneRaw);
+ user = resolveUserByPhoneForWxLogin(openId, session.getUnionId(), phone, phoneRaw);
}
-
- if (MiniLoginIntent.VISITOR.equals(req.getLoginIntent())) {
- if (user == null) {
- MpUser created = new MpUser();
- created.setOpenId(openId);
- created.setUnionId(session.getUnionId());
- created.setUserType(MiniUserType.VISITOR);
- created.setMobile(phoneRaw);
- created.setStatus(1);
- mpUserMapper.insert(created);
- user = mpUserMapper.selectById(created.getId());
- } else {
- assertAccountEnabled(user);
- if (!MiniUserType.VISITOR.equals(user.getUserType())) {
- throw new BizException(
- BizErrorCode.MINI_LOGIN_INTENT_MISMATCH, "当前微信已登记为员工,请使用员工入口登录");
- }
- assertPhoneMatchesStored(user, phone);
- syncMpUserMobile(user, phoneRaw);
- if (user.getUnionId() == null && session.getUnionId() != null) {
- user.setUnionId(session.getUnionId());
- mpUserMapper.updateById(user);
- }
- }
- MiniStpUtil.login(user.getId());
- return buildResponse(user);
- }
-
- throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "loginIntent 无效");
+ assertUserCanLogin(user);
+ syncUnionIdIfNeeded(user, session.getUnionId());
+ MiniStpUtil.login(user.getId());
+ return buildResponse(user);
}
@Transactional(rollbackFor = Exception.class)
@@ -130,15 +84,44 @@
.orElse(null);
if (user == null) {
user = registerVisitorForPhoneLogin(mobileRaw);
- } else {
- assertAccountEnabled(user);
}
+ assertUserCanLogin(user);
+ MiniStpUtil.login(user.getId());
+ return buildResponse(user);
+ }
+
+ private MpUser resolveUserByPhoneForWxLogin(
+ String openId, String unionId, String normalizedPhone, String phoneRaw) {
+ if (!normalizedPhone.matches("^\\d{11}$")) {
+ throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "手机号格式不正确");
+ }
+ List<MpUser> users =
+ mpUserMapper.selectList(
+ new LambdaQueryWrapper<MpUser>()
+ .eq(MpUser::getDelFlag, 0));
+ MpUser user =
+ users.stream()
+ .filter(Objects::nonNull)
+ .filter(u -> normalizedPhone.equals(PhoneNormalize.mainland(u.getMobile())))
+ .sorted(this::compareByLoginPriority)
+ .findFirst()
+ .orElse(null);
+ if (user == null) {
+ MpUser created = new MpUser();
+ created.setOpenId(openId);
+ created.setUnionId(unionId);
+ created.setUserType(MiniUserType.VISITOR);
+ created.setMobile(phoneRaw);
+ created.setStatus(1);
+ mpUserMapper.insert(created);
+ return mpUserMapper.selectById(created.getId());
+ }
+ assertAccountEnabled(user);
if (MiniUserType.EMPLOYEE.equals(user.getUserType()) && user.getDeptId() == null) {
throw new BizException(BizErrorCode.MINI_STAFF_NOT_BOUND, "员工未分配部门");
}
- ensureOpenIdForPhoneLogin(user);
- MiniStpUtil.login(user.getId());
- return buildResponse(user);
+ bindOpenIdIfNeeded(user, openId, unionId, phoneRaw);
+ return mpUserMapper.selectById(user.getId());
}
/**
@@ -171,16 +154,6 @@
return null;
}
- private void assertPhoneMatchesStored(MpUser user, String normalizedPhone) {
- if (user.getMobile() == null || user.getMobile().isBlank()) {
- return;
- }
- String stored = PhoneNormalize.mainland(user.getMobile());
- if (!stored.isBlank() && !stored.equals(normalizedPhone)) {
- throw new BizException(BizErrorCode.MINI_PHONE_MISMATCH, "手机号与登记信息不一致");
- }
- }
-
private void syncMpUserMobile(MpUser user, String phoneRaw) {
boolean needUpdate = false;
if (user.getMobile() == null || user.getMobile().isBlank()) {
@@ -190,6 +163,57 @@
if (needUpdate) {
mpUserMapper.updateById(user);
}
+ }
+
+ private void bindOpenIdIfNeeded(MpUser user, String openId, String unionId, String phoneRaw) {
+ if (user == null) {
+ return;
+ }
+ String currentOpenId = user.getOpenId();
+ if (StringUtils.hasText(currentOpenId)
+ && !Objects.equals(currentOpenId, openId)
+ && !MpStaffConstants.isPlaceholderOpenId(currentOpenId)) {
+ throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "该手机号已绑定其他微信账号");
+ }
+ if (MiniUserType.EMPLOYEE.equals(user.getUserType())
+ && MpStaffConstants.isPlaceholderOpenId(currentOpenId)) {
+ MpUser bound = tryBindPreRegisteredEmployee(openId, unionId, PhoneNormalize.mainland(phoneRaw), phoneRaw);
+ if (bound == null) {
+ throw new BizException(BizErrorCode.MINI_STAFF_NOT_BOUND, "员工未登记,请联系管理员开通后再登录");
+ }
+ return;
+ }
+ boolean needUpdate = false;
+ if (!Objects.equals(currentOpenId, openId)) {
+ user.setOpenId(openId);
+ needUpdate = true;
+ }
+ if (!StringUtils.hasText(user.getUnionId()) && StringUtils.hasText(unionId)) {
+ user.setUnionId(unionId);
+ needUpdate = true;
+ }
+ if (!StringUtils.hasText(user.getMobile()) && StringUtils.hasText(phoneRaw)) {
+ user.setMobile(phoneRaw);
+ needUpdate = true;
+ }
+ if (needUpdate) {
+ mpUserMapper.updateById(user);
+ }
+ }
+
+ private void assertUserCanLogin(MpUser user) {
+ assertAccountEnabled(user);
+ if (MiniUserType.EMPLOYEE.equals(user.getUserType()) && user.getDeptId() == null) {
+ throw new BizException(BizErrorCode.MINI_STAFF_NOT_BOUND, "员工未分配部门");
+ }
+ }
+
+ private void syncUnionIdIfNeeded(MpUser user, String unionId) {
+ if (user == null || !StringUtils.hasText(unionId) || StringUtils.hasText(user.getUnionId())) {
+ return;
+ }
+ user.setUnionId(unionId);
+ mpUserMapper.updateById(user);
}
private void assertAccountEnabled(MpUser user) {
@@ -223,14 +247,6 @@
return 2;
}
- private void ensureOpenIdForPhoneLogin(MpUser user) {
- if (StringUtils.hasText(user.getOpenId())) {
- return;
- }
- user.setOpenId(H5_PHONE_OPEN_ID_PREFIX + user.getId());
- mpUserMapper.updateById(user);
- }
-
private MpUser registerVisitorForPhoneLogin(String mobileRaw) {
MpUser created = new MpUser();
created.setUserType(MiniUserType.VISITOR);
@@ -248,6 +264,27 @@
}
assertAccountEnabled(u);
return u;
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public MpUser updateProfile(MiniProfileUpdateRequest request) {
+ MpUser user = currentMpUser();
+ String nickName = trimRequired(request.getNickName(), "姓名不能为空");
+ if (nickName.length() > 30) {
+ throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "姓名长度不能超过30个字符");
+ }
+ String gender = trimToNull(request.getGender());
+ if (StringUtils.hasText(gender) && !"男".equals(gender) && !"女".equals(gender)) {
+ throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "性别仅支持男或女");
+ }
+ String companyName = trimToNull(request.getCompanyName());
+ String avatarUrl = trimToNull(request.getAvatarUrl());
+ user.setNickName(nickName);
+ user.setGender(gender);
+ user.setCompanyName(companyName);
+ user.setAvatarUrl(avatarUrl);
+ mpUserMapper.updateById(user);
+ return mpUserMapper.selectById(user.getId());
}
public void logout() {
@@ -276,7 +313,24 @@
.deptName(deptName)
.deptLeader(leader)
.avatarUrl(user.getAvatarUrl())
+ .companyName(user.getCompanyName())
.displayName(name)
.build();
}
+
+ private static String trimToNull(String value) {
+ if (!StringUtils.hasText(value)) {
+ return null;
+ }
+ String trimmed = value.trim();
+ return trimmed.isEmpty() ? null : trimmed;
+ }
+
+ private static String trimRequired(String value, String message) {
+ String trimmed = trimToNull(value);
+ if (!StringUtils.hasText(trimmed)) {
+ throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, message);
+ }
+ return trimmed;
+ }
}
--
Gitblit v1.7.1