package com.tcm.training.admin.user.service;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.tcm.training.admin.common.PageResponse;
|
import com.tcm.training.admin.user.dto.AccountCreateRequest;
|
import com.tcm.training.admin.user.dto.AccountResetPasswordRequest;
|
import com.tcm.training.admin.user.dto.AccountStatusRequest;
|
import com.tcm.training.admin.user.dto.AccountUpdateRequest;
|
import com.tcm.training.admin.user.entity.SysRole;
|
import com.tcm.training.admin.user.entity.SysUser;
|
import com.tcm.training.admin.user.entity.SysUserRole;
|
import com.tcm.training.admin.user.mapper.SysRoleMapper;
|
import com.tcm.training.admin.user.mapper.SysUserMapper;
|
import com.tcm.training.admin.user.mapper.SysUserRoleMapper;
|
import com.tcm.training.admin.user.row.AccountDetailRow;
|
import com.tcm.training.admin.user.row.AccountListRow;
|
import com.tcm.training.admin.user.vo.AccountDetailVO;
|
import com.tcm.training.admin.user.vo.AccountListItemVO;
|
import com.tcm.training.admin.user.vo.AccountStatusVO;
|
import com.tcm.training.admin.user.vo.RoleOptionVO;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.time.LocalDateTime;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.regex.Pattern;
|
|
@Service
|
public class AccountAppService {
|
|
private static final Pattern PASSWORD_PATTERN = Pattern.compile(
|
"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^A-Za-z\\d]).{12,64}$"
|
);
|
|
private final SysUserMapper sysUserMapper;
|
private final SysRoleMapper sysRoleMapper;
|
private final SysUserRoleMapper sysUserRoleMapper;
|
private final BCryptPasswordEncoder passwordEncoder;
|
|
public AccountAppService(
|
SysUserMapper sysUserMapper,
|
SysRoleMapper sysRoleMapper,
|
SysUserRoleMapper sysUserRoleMapper,
|
BCryptPasswordEncoder passwordEncoder
|
) {
|
this.sysUserMapper = sysUserMapper;
|
this.sysRoleMapper = sysRoleMapper;
|
this.sysUserRoleMapper = sysUserRoleMapper;
|
this.passwordEncoder = passwordEncoder;
|
}
|
|
public PageResponse<AccountListItemVO> page(
|
int page,
|
int pageSize,
|
String realName,
|
String phone,
|
Long roleId,
|
Integer status
|
) {
|
IPage<AccountListRow> records = sysUserMapper.selectAccountPage(
|
new Page<AccountListRow>(page, pageSize),
|
realName,
|
phone,
|
roleId,
|
status
|
);
|
|
List<AccountListItemVO> list = new ArrayList<AccountListItemVO>();
|
for (AccountListRow row : records.getRecords()) {
|
AccountListItemVO vo = new AccountListItemVO();
|
vo.setId(row.getId());
|
vo.setRealName(row.getRealName());
|
vo.setUsername(row.getUsername());
|
vo.setPhone(row.getPhone());
|
vo.setRoleId(row.getRoleId());
|
vo.setRoleName(row.getRoleName());
|
vo.setStatus(row.getStatus());
|
vo.setCreatedAt(row.getCreatedAt());
|
list.add(vo);
|
}
|
return PageResponse.of(list, records.getTotal(), records.getCurrent(), records.getSize());
|
}
|
|
public AccountDetailVO detail(Long id) {
|
AccountDetailRow row = sysUserMapper.selectAccountDetail(id);
|
if (row == null) {
|
throw new IllegalArgumentException("帐号不存在");
|
}
|
return toDetailVO(row);
|
}
|
|
@Transactional
|
public AccountDetailVO create(AccountCreateRequest req) {
|
validatePassword(req.getInitialPassword());
|
String username = req.getUsername().trim();
|
String phone = req.getPhone().trim();
|
ensureUsernameUnique(username, null);
|
ensurePhoneUnique(phone, null);
|
SysRole role = requireRole(req.getRoleId());
|
|
SysUser user = new SysUser();
|
user.setUsername(username);
|
user.setNickname(req.getRealName().trim());
|
user.setRealName(req.getRealName().trim());
|
user.setPhone(phone);
|
user.setStatus(req.getStatus());
|
user.setDeleted(0);
|
user.setPassword(passwordEncoder.encode(req.getInitialPassword()));
|
user.setCreatedAt(LocalDateTime.now());
|
user.setUpdatedAt(LocalDateTime.now());
|
sysUserMapper.insert(user);
|
|
bindSingleRole(user.getId(), role.getId());
|
return detail(user.getId());
|
}
|
|
@Transactional
|
public AccountDetailVO update(Long id, AccountUpdateRequest req) {
|
SysUser user = requireUser(id);
|
String phone = req.getPhone().trim();
|
ensurePhoneUnique(phone, id);
|
SysRole role = requireRole(req.getRoleId());
|
|
user.setNickname(req.getRealName().trim());
|
user.setRealName(req.getRealName().trim());
|
user.setPhone(phone);
|
user.setStatus(req.getStatus());
|
sysUserMapper.updateById(user);
|
|
bindSingleRole(id, role.getId());
|
return detail(id);
|
}
|
|
@Transactional
|
public AccountStatusVO patchStatus(Long id, AccountStatusRequest req) {
|
SysUser user = requireUser(id);
|
user.setStatus(req.getStatus());
|
sysUserMapper.updateById(user);
|
return new AccountStatusVO(id, req.getStatus());
|
}
|
|
@Transactional
|
public void resetPassword(Long id, AccountResetPasswordRequest req) {
|
SysUser user = requireUser(id);
|
if (!req.getNewPassword().equals(req.getConfirmPassword())) {
|
throw new IllegalArgumentException("两次密码输入不一致");
|
}
|
validatePassword(req.getNewPassword());
|
user.setPassword(passwordEncoder.encode(req.getNewPassword()));
|
sysUserMapper.updateById(user);
|
}
|
|
@Transactional
|
public void delete(Long id) {
|
SysUser user = requireUser(id);
|
user.setStatus(0);
|
sysUserMapper.updateById(user);
|
sysUserMapper.deleteById(id);
|
sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
|
.eq(SysUserRole::getUserId, id));
|
}
|
|
public List<RoleOptionVO> listRoleOptions() {
|
List<SysRole> roles = sysRoleMapper.selectList(new LambdaQueryWrapper<SysRole>()
|
.eq(SysRole::getDeleted, 0)
|
.eq(SysRole::getStatus, 1)
|
.orderByAsc(SysRole::getId));
|
List<RoleOptionVO> list = new ArrayList<RoleOptionVO>();
|
for (SysRole role : roles) {
|
list.add(new RoleOptionVO(role.getId(), role.getRoleName(), role.getRoleCode()));
|
}
|
return list;
|
}
|
|
private SysUser requireUser(Long id) {
|
SysUser user = sysUserMapper.selectOne(new LambdaQueryWrapper<SysUser>()
|
.eq(SysUser::getId, id)
|
.eq(SysUser::getDeleted, 0)
|
.last("limit 1"));
|
if (user == null) {
|
throw new IllegalArgumentException("帐号不存在");
|
}
|
return user;
|
}
|
|
private SysRole requireRole(Long roleId) {
|
SysRole role = sysRoleMapper.selectOne(new LambdaQueryWrapper<SysRole>()
|
.eq(SysRole::getId, roleId)
|
.eq(SysRole::getDeleted, 0)
|
.eq(SysRole::getStatus, 1)
|
.last("limit 1"));
|
if (role == null) {
|
throw new IllegalArgumentException("所属角色不存在或已禁用");
|
}
|
return role;
|
}
|
|
private void ensureUsernameUnique(String username, Long excludeId) {
|
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
|
.eq(SysUser::getUsername, username);
|
if (excludeId != null) {
|
wrapper.ne(SysUser::getId, excludeId);
|
}
|
SysUser exists = sysUserMapper.selectOne(wrapper.last("limit 1"));
|
if (exists != null) {
|
throw new IllegalArgumentException("登录帐号已存在");
|
}
|
}
|
|
private void ensurePhoneUnique(String phone, Long excludeId) {
|
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
|
.eq(SysUser::getPhone, phone);
|
if (excludeId != null) {
|
wrapper.ne(SysUser::getId, excludeId);
|
}
|
SysUser exists = sysUserMapper.selectOne(wrapper.last("limit 1"));
|
if (exists != null) {
|
throw new IllegalArgumentException("联系电话已被占用");
|
}
|
}
|
|
private void bindSingleRole(Long userId, Long roleId) {
|
sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
|
.eq(SysUserRole::getUserId, userId));
|
SysUserRole relation = new SysUserRole();
|
relation.setUserId(userId);
|
relation.setRoleId(roleId);
|
relation.setCreatedAt(LocalDateTime.now());
|
sysUserRoleMapper.insert(relation);
|
}
|
|
private void validatePassword(String password) {
|
if (!PASSWORD_PATTERN.matcher(password).matches()) {
|
throw new IllegalArgumentException("密码需至少12位,且包含大小写字母、数字和特殊字符");
|
}
|
}
|
|
private AccountDetailVO toDetailVO(AccountDetailRow row) {
|
AccountDetailVO vo = new AccountDetailVO();
|
vo.setId(row.getId());
|
vo.setRealName(row.getRealName());
|
vo.setUsername(row.getUsername());
|
vo.setPhone(row.getPhone());
|
vo.setRoleId(row.getRoleId());
|
vo.setRoleName(row.getRoleName());
|
vo.setStatus(row.getStatus());
|
vo.setCreatedAt(row.getCreatedAt());
|
vo.setUpdatedAt(row.getUpdatedAt());
|
return vo;
|
}
|
}
|