longz
2026-06-29 9d4cbff7464ebfd7803c2ce53ded49d0f73fe011
backend/src/main/java/com/sinata/appointment/service/SysUserApplicationService.java
@@ -6,6 +6,8 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sinata.appointment.constants.BizErrorCode;
import com.sinata.appointment.dto.ResetPasswordRequest;
import com.sinata.appointment.dto.CurrentUserPasswordUpdateRequest;
import com.sinata.appointment.dto.CurrentUserUpdateRequest;
import com.sinata.appointment.dto.SysUserCreateRequest;
import com.sinata.appointment.dto.SysUserDetailVo;
import com.sinata.appointment.dto.SysUserListVo;
@@ -35,6 +37,7 @@
@Service
@RequiredArgsConstructor
public class SysUserApplicationService {
    private static final String SUPER_ADMIN_USERNAME = "admin";
    private final SysUserMapper sysUserMapper;
    private final SysRoleMapper sysRoleMapper;
@@ -101,6 +104,42 @@
    public SysUserDetailVo getDetail(Long id, String uuid) {
        SysUser u = loadActiveWithUuid(id, uuid);
        return toDetailVo(u);
    }
    public SysUserDetailVo getCurrentUserDetail(long currentUserId) {
        SysUser u = loadActive(currentUserId);
        return toDetailVo(u);
    }
    @Transactional(rollbackFor = Exception.class)
    public SysUserDetailVo updateCurrentUser(long currentUserId, CurrentUserUpdateRequest req) {
        SysUser u = loadActive(currentUserId);
        u.setRealName(trimToNull(req.getRealName()));
        u.setMobile(trimToNull(req.getMobile()));
        u.setAvatarUrl(trimToNull(req.getAvatarUrl()));
        sysUserMapper.updateById(u);
        return toDetailVo(u);
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateCurrentPassword(long currentUserId, CurrentUserPasswordUpdateRequest req) {
        SysUser u = loadActive(currentUserId);
        if (!StringUtils.hasText(req.getOldPassword())) {
            throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "原密码不能为空");
        }
        if (!bcrypt.matches(req.getOldPassword(), u.getPasswordHash())) {
            throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "原密码不正确");
        }
        validateStrongPassword(req.getNewPassword());
        if (!Objects.equals(req.getNewPassword(), req.getNewPasswordConfirm())) {
            throw new BizException(BizErrorCode.PASSWORD_CONFIRM_MISMATCH, "两次输入的新密码不一致");
        }
        u.setPasswordHash(bcrypt.encode(req.getNewPassword()));
        sysUserMapper.updateById(u);
    }
    private SysUserDetailVo toDetailVo(SysUser u) {
        SysUserDetailVo vo = new SysUserDetailVo();
        vo.setId(u.getId());
        vo.setUuid(u.getUuid());
@@ -109,7 +148,7 @@
        vo.setMobile(u.getMobile());
        vo.setAvatarUrl(u.getAvatarUrl());
        vo.setStatus(u.getStatus());
        vo.setRoleIds(listRoleIds(id));
        vo.setRoleIds(listRoleIds(u.getId()));
        return vo;
    }
@@ -123,6 +162,7 @@
        if (exists > 0) {
            throw new BizException(BizErrorCode.DUPLICATE_USERNAME, "登录账号已存在");
        }
        validateStrongPassword(req.getPassword());
        validateRoleIds(req.getRoleIds());
        SysUser u = new SysUser();
@@ -157,6 +197,7 @@
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(Long id, ResetPasswordRequest req) {
        validateStrongPassword(req.getNewPassword());
        if (!Objects.equals(req.getNewPassword(), req.getNewPasswordConfirm())) {
            throw new BizException(BizErrorCode.PASSWORD_CONFIRM_MISMATCH, "两次输入的新密码不一致");
        }
@@ -176,6 +217,9 @@
            throw new BizException(BizErrorCode.USER_SELF_FORBIDDEN, "不能禁用自己的账号");
        }
        SysUser u = loadActiveWithUuid(id, req.getUuid());
        if (st == 0 && isSuperAdmin(u)) {
            throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "超级管理员账号不可禁用");
        }
        u.setStatus(st);
        sysUserMapper.updateById(u);
        if (st == 0) {
@@ -189,6 +233,9 @@
            throw new BizException(BizErrorCode.USER_SELF_FORBIDDEN, "不能删除自己的账号");
        }
        SysUser u = loadActiveWithUuid(id, uuid);
        if (isSuperAdmin(u)) {
            throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "超级管理员账号不可删除");
        }
        sysUserRoleMapper.delete(
                new LambdaQueryWrapper<SysUserRole>()
                        .eq(SysUserRole::getUserId, id)
@@ -205,11 +252,16 @@
    }
    private SysUser loadActiveWithUuid(Long id, String uuid) {
        SysUser u = loadActive(id);
        UuidAssert.match(u, uuid);
        return u;
    }
    private SysUser loadActive(Long id) {
        SysUser u = sysUserMapper.selectById(id);
        if (u == null || u.getDelFlag() != null && u.getDelFlag() == 1) {
            throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "资源不存在或无权访问");
        }
        UuidAssert.match(u, uuid);
        return u;
    }
@@ -256,4 +308,26 @@
        String t = s.trim();
        return t.isEmpty() ? null : t;
    }
    private static boolean isSuperAdmin(SysUser u) {
        return u != null && SUPER_ADMIN_USERNAME.equalsIgnoreCase(u.getUsername());
    }
    private static void validateStrongPassword(String password) {
        if (!StringUtils.hasText(password)) {
            throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "密码不能为空");
        }
        String value = password.trim();
        boolean ok =
                value.length() >= 12
                        && value.length() <= 64
                        && value.matches(".*[a-z].*")
                        && value.matches(".*[A-Z].*")
                        && value.matches(".*[^A-Za-z0-9].*");
        if (!ok) {
            throw new BizException(
                    BizErrorCode.AUTH_INVALID_CREDENTIALS,
                    "请输入至少12位含大小写字母、特殊字符的密码");
        }
    }
}