feat: 支持系统账号批量操作

- 新增账号批量删除和批量重置密码接口及结果返回

- 用户列表增加批量操作工具栏与结果提示

- 账号删除切换为逻辑删除语义
This commit is contained in:
2026-03-24 18:37:32 +08:00
parent d510034abb
commit 6e1bd73cd8
12 changed files with 513 additions and 14 deletions

View File

@@ -115,6 +115,12 @@ public class SysAccountBase extends DateEntity implements Serializable {
@Column(comment = "备注")
private String remark;
/**
* 删除标识
*/
@Column(value = "is_deleted", isLogicDelete = true, comment = "删除标识")
private BigInteger isDeleted;
public BigInteger getId() {
return id;
}
@@ -251,4 +257,12 @@ public class SysAccountBase extends DateEntity implements Serializable {
this.remark = remark;
}
public BigInteger getIsDeleted() {
return isDeleted;
}
public void setIsDeleted(BigInteger isDeleted) {
this.isDeleted = isDeleted;
}
}

View File

@@ -0,0 +1,39 @@
package tech.easyflow.system.entity.vo;
import java.math.BigInteger;
/**
* 用户批量操作失败项。
*/
public class SysAccountBatchActionErrorItemVo {
private BigInteger id;
private String loginName;
private String reason;
public BigInteger getId() {
return id;
}
public void setId(BigInteger id) {
this.id = id;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}

View File

@@ -0,0 +1,50 @@
package tech.easyflow.system.entity.vo;
import java.util.ArrayList;
import java.util.List;
/**
* 用户批量操作结果。
*/
public class SysAccountBatchActionResultVo {
private int successCount = 0;
private int errorCount = 0;
private int totalCount = 0;
private List<SysAccountBatchActionErrorItemVo> errorItems = new ArrayList<>();
public int getSuccessCount() {
return successCount;
}
public void setSuccessCount(int successCount) {
this.successCount = successCount;
}
public int getErrorCount() {
return errorCount;
}
public void setErrorCount(int errorCount) {
this.errorCount = errorCount;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public List<SysAccountBatchActionErrorItemVo> getErrorItems() {
return errorItems;
}
public void setErrorItems(List<SysAccountBatchActionErrorItemVo> errorItems) {
this.errorItems = errorItems;
}
}

View File

@@ -4,10 +4,12 @@ import com.mybatisflex.core.service.IService;
import org.springframework.web.multipart.MultipartFile;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.system.entity.SysAccount;
import tech.easyflow.system.entity.vo.SysAccountBatchActionResultVo;
import tech.easyflow.system.entity.vo.SysAccountImportResultVo;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Collection;
/**
* 用户表 服务层。
@@ -23,6 +25,10 @@ public interface SysAccountService extends IService<SysAccount> {
void resetPassword(BigInteger accountId, BigInteger operatorId);
SysAccountBatchActionResultVo removeBatchWithResult(Collection<BigInteger> ids);
SysAccountBatchActionResultVo resetPasswordBatch(Collection<BigInteger> ids, BigInteger operatorId);
SysAccountImportResultVo importAccounts(MultipartFile file, LoginAccount loginAccount);
void writeImportTemplate(OutputStream outputStream);

View File

@@ -26,6 +26,8 @@ import tech.easyflow.system.entity.SysAccountRole;
import tech.easyflow.system.entity.SysDept;
import tech.easyflow.system.entity.SysPosition;
import tech.easyflow.system.entity.SysRole;
import tech.easyflow.system.entity.vo.SysAccountBatchActionErrorItemVo;
import tech.easyflow.system.entity.vo.SysAccountBatchActionResultVo;
import tech.easyflow.system.entity.vo.SysAccountImportErrorRowVo;
import tech.easyflow.system.entity.vo.SysAccountImportResultVo;
import tech.easyflow.system.mapper.SysAccountMapper;
@@ -42,6 +44,7 @@ import java.io.OutputStream;
import java.math.BigInteger;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@@ -164,13 +167,7 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
if (record == null) {
throw new BusinessException("用户不存在");
}
Integer accountType = record.getAccountType();
if (EnumAccountType.SUPER_ADMIN.getCode().equals(accountType)) {
throw new BusinessException("不能重置超级管理员密码");
}
if (EnumAccountType.TENANT_ADMIN.getCode().equals(accountType)) {
throw new BusinessException("不能重置租户管理员密码");
}
validateResetPasswordAllowed(record);
SysAccount update = new SysAccount();
update.setId(accountId);
update.setPassword(BCrypt.hashpw(DEFAULT_RESET_PASSWORD));
@@ -181,6 +178,62 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
StpUtil.kickout(accountId);
}
@Override
public SysAccountBatchActionResultVo removeBatchWithResult(Collection<BigInteger> ids) {
List<BigInteger> accountIds = normalizeAccountIds(ids);
SysAccountBatchActionResultVo result = initBatchActionResult(accountIds);
if (accountIds.isEmpty()) {
return result;
}
for (BigInteger accountId : accountIds) {
SysAccount record = getById(accountId);
if (record == null) {
appendBatchError(result, accountId, null, "用户不存在");
continue;
}
try {
validateRemoveAllowed(record);
executeInRowTransaction(() -> {
boolean success = removeById(accountId);
if (!success) {
throw new BusinessException("删除失败");
}
});
result.setSuccessCount(result.getSuccessCount() + 1);
} catch (Exception e) {
appendBatchError(result, accountId, record.getLoginName(), extractErrorMessage(e, "删除失败"));
}
}
result.setErrorCount(result.getErrorItems().size());
return result;
}
@Override
public SysAccountBatchActionResultVo resetPasswordBatch(Collection<BigInteger> ids, BigInteger operatorId) {
List<BigInteger> accountIds = normalizeAccountIds(ids);
SysAccountBatchActionResultVo result = initBatchActionResult(accountIds);
if (accountIds.isEmpty()) {
return result;
}
for (BigInteger accountId : accountIds) {
SysAccount record = getById(accountId);
if (record == null) {
appendBatchError(result, accountId, null, "用户不存在");
continue;
}
try {
executeInRowTransaction(() -> resetPassword(accountId, operatorId));
result.setSuccessCount(result.getSuccessCount() + 1);
} catch (Exception e) {
appendBatchError(result, accountId, record.getLoginName(), extractErrorMessage(e, "重置密码失败"));
}
}
result.setErrorCount(result.getErrorItems().size());
return result;
}
@Override
public SysAccountImportResultVo importAccounts(MultipartFile file, LoginAccount loginAccount) {
validateImportFile(file);
@@ -418,9 +471,21 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
result.getErrorRows().add(errorRow);
}
private void appendBatchError(SysAccountBatchActionResultVo result, BigInteger id, String loginName, String reason) {
SysAccountBatchActionErrorItemVo errorItem = new SysAccountBatchActionErrorItemVo();
errorItem.setId(id);
errorItem.setLoginName(loginName);
errorItem.setReason(reason);
result.getErrorItems().add(errorItem);
}
private String extractImportErrorMessage(Exception e) {
return extractErrorMessage(e, "导入失败");
}
private String extractErrorMessage(Exception e, String defaultMessage) {
if (e == null) {
return "导入失败";
return defaultMessage;
}
if (e.getCause() != null && StringUtil.hasText(e.getCause().getMessage())) {
return e.getCause().getMessage();
@@ -428,7 +493,46 @@ public class SysAccountServiceImpl extends ServiceImpl<SysAccountMapper, SysAcco
if (StringUtil.hasText(e.getMessage())) {
return e.getMessage();
}
return "导入失败";
return defaultMessage;
}
private void validateResetPasswordAllowed(SysAccount record) {
Integer accountType = record.getAccountType();
if (EnumAccountType.SUPER_ADMIN.getCode().equals(accountType)) {
throw new BusinessException("不能重置超级管理员密码");
}
if (EnumAccountType.TENANT_ADMIN.getCode().equals(accountType)) {
throw new BusinessException("不能重置租户管理员密码");
}
}
private void validateRemoveAllowed(SysAccount record) {
Integer accountType = record.getAccountType();
if (EnumAccountType.SUPER_ADMIN.getCode().equals(accountType)) {
throw new BusinessException("不能删除超级管理员");
}
if (EnumAccountType.TENANT_ADMIN.getCode().equals(accountType)) {
throw new BusinessException("不能删除租户管理员");
}
}
private List<BigInteger> normalizeAccountIds(Collection<BigInteger> ids) {
if (ids == null || ids.isEmpty()) {
return Collections.emptyList();
}
LinkedHashSet<BigInteger> uniqueIds = new LinkedHashSet<>();
for (BigInteger id : ids) {
if (id != null) {
uniqueIds.add(id);
}
}
return new ArrayList<>(uniqueIds);
}
private SysAccountBatchActionResultVo initBatchActionResult(List<BigInteger> accountIds) {
SysAccountBatchActionResultVo result = new SysAccountBatchActionResultVo();
result.setTotalCount(accountIds.size());
return result;
}
private List<List<String>> buildImportHeadList() {