“mitao”
2026-04-27 b82daad16c59c9770f6a0492e1a89514d41e6f71
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/register/service/AppRegisterService.java
@@ -8,6 +8,7 @@
import com.tcm.training.admin.app.integration.haizhentong.entity.HztClinic;
import com.tcm.training.admin.app.integration.haizhentong.mapper.HztAppUserMapper;
import com.tcm.training.admin.app.integration.haizhentong.mapper.HztClinicMapper;
import com.tcm.training.admin.app.share.service.AppShareService;
import com.tcm.training.admin.app.register.dto.AppRegisterOperatorCompleteRequest;
import com.tcm.training.admin.app.register.dto.AppRegisterOperatorPrepareRequest;
import com.tcm.training.admin.app.register.dto.AppRegisterUserRequest;
@@ -54,6 +55,7 @@
    private final HztClinicMapper hztClinicMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final ObjectMapper objectMapper;
    private final AppShareService appShareService;
    /**
     * 注入注册链路所需的本地库、海诊通库、验证码与缓存能力。
@@ -66,7 +68,8 @@
                              HztAppUserMapper hztAppUserMapper,
                              HztClinicMapper hztClinicMapper,
                              StringRedisTemplate stringRedisTemplate,
                              ObjectMapper objectMapper) {
                              ObjectMapper objectMapper,
                              AppShareService appShareService) {
        this.userMapper = userMapper;
        this.clinicMapper = clinicMapper;
        this.passwordEncoder = passwordEncoder;
@@ -76,6 +79,7 @@
        this.hztClinicMapper = hztClinicMapper;
        this.stringRedisTemplate = stringRedisTemplate;
        this.objectMapper = objectMapper;
        this.appShareService = appShareService;
    }
    /**
@@ -109,6 +113,7 @@
        String phone = normalizePhone(request.getPhone());
        String password = normalizePassword(request.getPassword());
        String inviteCode = normalizeInviteCode(request.getInviteCode());
        String bindTicket = normalizeBindTicket(request.getBindTicket());
        ensurePhoneAvailable(phone);
        appSmsCodeService.validateRegisterCode(phone, normalizeCode(request.getCode()));
@@ -123,8 +128,8 @@
        HztAppUser hztAppUser = findHztAppUserByPhone(phone);
        populateUserProfile(user, hztAppUser, phone);
        // 邀请码命中时绑定上级诊所用户,并继承该诊所关系。
        bindSuperiorClinicIfNecessary(user, inviteCode);
        // 绑定票据优先于邀请码,避免安装后丢失或误填导致关系错误。
        bindSuperiorClinicIfNecessary(user, inviteCode, bindTicket);
        userMapper.insert(user);
        return new AppRegisterResultVO(user.getId(), user.getType(), user.getClinicId(), null);
@@ -206,27 +211,26 @@
    /**
     * 按邀请码绑定本地上级诊所用户与诊所归属。
     */
    private void bindSuperiorClinicIfNecessary(AppUser user, String inviteCode) {
        if (inviteCode == null) {
    private void bindSuperiorClinicIfNecessary(AppUser user, String inviteCode, String bindTicket) {
        AppShareService.InviteBindingTarget bindingTarget = resolveInviteBindingTarget(inviteCode, bindTicket);
        if (bindingTarget == null) {
            return;
        }
        Clinic clinic = clinicMapper.selectOne(new LambdaQueryWrapper<Clinic>()
                .eq(Clinic::getInviteCode, inviteCode)
                .eq(Clinic::getDeleted, 0)
                .last("limit 1"));
        if (clinic == null) {
            throw new IllegalArgumentException("邀请码无效");
        user.setClinicId(bindingTarget.getClinicId());
        user.setSuperiorClinicUserId(bindingTarget.getSuperiorClinicUserId());
    }
    /**
     * 解析注册阶段应绑定的目标关系,票据优先于邀请码。
     */
    private AppShareService.InviteBindingTarget resolveInviteBindingTarget(String inviteCode, String bindTicket) {
        if (bindTicket != null) {
            return appShareService.consumeBindTicket(bindTicket);
        }
        AppUser clinicUser = userMapper.selectOne(new LambdaQueryWrapper<AppUser>()
                .eq(AppUser::getClinicId, clinic.getId())
                .eq(AppUser::getType, 1)
                .eq(AppUser::getDeleted, 0)
                .last("limit 1"));
        if (clinicUser == null) {
            throw new IllegalArgumentException("邀请码暂不可用,请联系诊所管理员");
        if (inviteCode == null) {
            return null;
        }
        user.setClinicId(clinicUser.getClinicId());
        user.setSuperiorClinicUserId(clinicUser.getId());
        return appShareService.resolveInviteBindingTarget(inviteCode);
    }
    /**
@@ -463,6 +467,13 @@
    }
    /**
     * 归一化绑定票据。
     */
    private String normalizeBindTicket(String bindTicket) {
        return trimToNull(bindTicket);
    }
    /**
     * 归一化经营者注册凭证。
     */
    private String normalizeRegisterTicket(String registerTicket) {