13404089107
2026-04-30 1cf6d1e5883cca7793884ca4151c70049cded9f0
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/settings/service/AppSettingsService.java
@@ -17,6 +17,7 @@
import com.tcm.training.admin.app.settings.vo.AppSettingsNotificationVO;
import com.tcm.training.admin.app.settings.vo.AppSettingsProfileVO;
import com.tcm.training.admin.app.settings.vo.AppSettingsWechatBindingVO;
import com.tcm.training.admin.app.share.service.AppShareService;
import com.tcm.training.admin.member.entity.AppUser;
import com.tcm.training.admin.member.mapper.UserMapper;
import com.tcm.training.admin.upload.ObsUploadService;
@@ -54,6 +55,7 @@
    private final AppSmsCodeService appSmsCodeService;
    private final BCryptPasswordEncoder passwordEncoder;
    private final AppWechatAuthClient appWechatAuthClient;
    private final AppShareService appShareService;
    private final AppUserNotificationSettingMapper appUserNotificationSettingMapper;
    private final ObsUploadService obsUploadService;
@@ -65,6 +67,7 @@
                              AppSmsCodeService appSmsCodeService,
                              BCryptPasswordEncoder passwordEncoder,
                              AppWechatAuthClient appWechatAuthClient,
                              AppShareService appShareService,
                              AppUserNotificationSettingMapper appUserNotificationSettingMapper,
                              ObsUploadService obsUploadService) {
        this.appAuthSessionService = appAuthSessionService;
@@ -72,6 +75,7 @@
        this.appSmsCodeService = appSmsCodeService;
        this.passwordEncoder = passwordEncoder;
        this.appWechatAuthClient = appWechatAuthClient;
        this.appShareService = appShareService;
        this.appUserNotificationSettingMapper = appUserNotificationSettingMapper;
        this.obsUploadService = obsUploadService;
    }
@@ -157,8 +161,25 @@
        requirePhoneAvailable(newPhone, user.getId());
        appSmsCodeService.validatePhoneChangeCode(newPhone, code);
        user.setPhone(newPhone);
        bindInviteRelationIfAbsent(user, request.getInviteCode());
        userMapper.updateById(user);
        return toProfileVO(user);
    }
    /**
     * 用户尚未绑定诊所关系时,根据医生邀请码补齐上下级关系。
     */
    private void bindInviteRelationIfAbsent(AppUser user, String inviteCode) {
        if (user.getClinicId() != null || user.getSuperiorClinicUserId() != null) {
            return;
        }
        String normalizedInviteCode = normalizeInviteCode(inviteCode);
        if (normalizedInviteCode == null) {
            return;
        }
        AppShareService.InviteBindingTarget bindingTarget = appShareService.resolveInviteBindingTarget(normalizedInviteCode);
        user.setClinicId(bindingTarget.getClinicId());
        user.setSuperiorClinicUserId(bindingTarget.getSuperiorClinicUserId());
    }
    /**
@@ -422,6 +443,18 @@
    }
    /**
     * 归一化医生邀请码,非法时忽略以保持绑定手机号主流程可用。
     */
    private String normalizeInviteCode(String inviteCode) {
        String normalized = trimToNull(inviteCode);
        if (normalized == null) {
            return null;
        }
        String upperInviteCode = normalized.toUpperCase();
        return upperInviteCode.matches("^[A-Z0-9]{6}$") ? upperInviteCode : null;
    }
    /**
     * 校验通知时间仅允许使用页面固定选项。
     */
    private Integer normalizeAdvanceMinutes(Integer advanceMinutes) {