BUGFIX:1、教育通过上传文件批量创建子账号没有任何校验

2、下载子账号所有信息接口缺失(原下载模板接口保留)
3、保存个人模特到collection时类型设置为System
4、创建子账号时设置积分无效
This commit is contained in:
2025-08-15 17:44:45 +08:00
parent c28db81893
commit 45d6af92e8
11 changed files with 138 additions and 30 deletions

View File

@@ -369,6 +369,12 @@ public class AccountController {
accountService.subAccountImportExcelDownload(response); accountService.subAccountImportExcelDownload(response);
} }
@GetMapping("/exportAccountsToExcel")
@ApiOperation(value = "下载子账号信息")
public void exportAccountsToExcel(HttpServletResponse response) {
accountService.exportAccountsToExcel(response);
}
@PostMapping("/subAccountImport") @PostMapping("/subAccountImport")
@ApiOperation(value = "模板导入") @ApiOperation(value = "模板导入")
public Response<Boolean> subAccountImport(@RequestParam("file") MultipartFile file) { public Response<Boolean> subAccountImport(@RequestParam("file") MultipartFile file) {

View File

@@ -19,4 +19,6 @@ public class GetNextSysElementVO {
@ApiModelProperty("对应的图片的绝对路径") @ApiModelProperty("对应的图片的绝对路径")
private String path; private String path;
public GetNextSysElementVO() {
}
} }

View File

@@ -233,6 +233,8 @@ public interface AccountService extends IService<Account> {
void subAccountImportExcelDownload(HttpServletResponse response); void subAccountImportExcelDownload(HttpServletResponse response);
void exportAccountsToExcel(HttpServletResponse response);
Boolean subAccountImport(MultipartFile file); Boolean subAccountImport(MultipartFile file);
Set<String> organizationNameSearch(String type, String name); Set<String> organizationNameSearch(String type, String name);

View File

@@ -39,6 +39,8 @@ import com.zaxxer.hikari.HikariDataSource;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -2162,7 +2164,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
int subUserRole = getSubUserRole(account.getSystemUser()); int subUserRole = getSubUserRole(account.getSystemUser());
if (addSubAccountDTO.getId() == null) { if (addSubAccountDTO.getId() == null) {
return createSubAccount(addSubAccountDTO, account, subUserRole, null, null); return createSubAccount(addSubAccountDTO, account, subUserRole, addSubAccountDTO.getCreditsUsageLimit(), null);
} else { } else {
return updateSubAccount(addSubAccountDTO, account, subUserRole); return updateSubAccount(addSubAccountDTO, account, subUserRole);
} }
@@ -3056,6 +3058,88 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
} }
} }
@Override
public void exportAccountsToExcel(HttpServletResponse response) {
Workbook workbook = null;
try {
// 1. 查询数据
Account adminAcc = baseMapper.selectById(UserContext.getUserHolder().getId());
List<Account> accounts = accountMapper.selectList(new QueryWrapper<Account>()
.eq("organization_name", adminAcc.getOrganizationName())
.eq("system_user", 8)
.select("user_name", "user_email", "user_password", "credits_usage_limit"));
// 2. 创建Excel工作簿
workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("subAccounts");
// 3. 创建标题行
Row headerRow = sheet.createRow(0);
String[] headers = {"name", "email", "password", "creditsUsageLimit"};
// 设置标题样式
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerStyle.setFont(headerFont);
// 写入标题
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerStyle);
}
// 4. 写入数据
int rowNum = 1;
for (Account account : accounts) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(account.getUserName() != null ? account.getUserName() : "");
row.createCell(1).setCellValue(account.getUserEmail() != null ? account.getUserEmail() : "");
row.createCell(2).setCellValue(account.getUserPassword() != null ? account.getUserPassword() : "");
// 更安全的数据类型处理
if (account.getCreditsUsageLimit() != null) {
row.createCell(3).setCellValue(String.valueOf(account.getCreditsUsageLimit()));
} else {
row.createCell(3).setCellValue(""); // 空字符串
}
}
// 5. 自动调整列宽
for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i);
}
// 6. 重置响应(重要!)
response.reset();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("UTF-8");
// 设置文件名(处理特殊字符)
String fileName = "subAccount_export.xlsx";
String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replace("+", "%20");
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
// 7. 写入响应流
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.flush();
} catch (IOException e) {
log.error(e.getMessage()); // 记录异常信息
throw new BusinessException("导出文件失败");
} finally {
// 确保资源关闭
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
log.error(e.getMessage()); // 记录异常信息
}
}
}
}
@Override @Override
public Boolean subAccountImport(MultipartFile file) { public Boolean subAccountImport(MultipartFile file) {
AuthPrincipalVo vo = UserContext.getUserHolder(); AuthPrincipalVo vo = UserContext.getUserHolder();
@@ -3069,29 +3153,24 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
// 示例:打印或保存 // 示例:打印或保存
for (SubAccountImportDTO dto : importList) { for (SubAccountImportDTO dto : importList) {
// 只有当前子账号数量为0时允许批量上传
QueryWrapper<Account> qw = new QueryWrapper<>();
qw.lambda().eq(Account::getSystemUser, 8)
.eq(Account::getOrganizationName, parent.getOrganizationName());
List<Account> accounts = accountMapper.selectList(qw);
if (!accounts.isEmpty()){
throw new BusinessException("permit.bulk.creation", ResultEnum.PROMPT.getCode());
}
if (importList.size() > parent.getSubAccountNum() - 1){
throw new BusinessException("Action required: You cannot create [" +importList.size() + "] sub-accounts (Current quota: [" + (parent.getSubAccountNum() - 1) + "]).");
}
Account account = new Account(); AddSubAccountDTO addSubAccountDTO = new AddSubAccountDTO();
account.setUserName(dto.getName()); addSubAccountDTO.setUserEmail(dto.getEmail());
account.setUserEmail(dto.getEmail()); addSubAccountDTO.setUserName(dto.getEmail().substring(0, dto.getEmail().indexOf("@")));
account.setUserPassword(md5(dto.getPassword() + "abc")); addSubAccountDTO.setUserPassword(md5(parent.getOrganizationName().toLowerCase() + "abc"));
account.setCreditsUsageLimit(BigDecimal.valueOf(dto.getCredisUsageLimit())); // 添加用户
account.setParentId(vo.getId()); addSubAccount(addSubAccountDTO);
account.setValidStartTime(parent.getValidStartTime());
account.setValidEndTime(parent.getValidEndTime());
account.setCreateDate(new Date());
account.setIsTrial(0);
account.setIsBeginner(1);
account.setCredits(BigDecimal.valueOf(0));
account.setLanguage(Language.ENGLISH.name());
if (parent.getSystemUser() == 5) {
account.setSystemUser(6);
}
if (parent.getSystemUser() == 7) {
account.setSystemUser(8);
}
account.setOrganizationName(parent.getOrganizationName());
account.setParentId(parent.getId());
accountMapper.insert(account);
} }
return true; return true;
@@ -3104,7 +3183,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
public static String md5(String input) { public static String md5(String input) {
try { try {
MessageDigest md = MessageDigest.getInstance("MD5"); MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(input.getBytes()); byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8));
// 转为16进制字符串 // 转为16进制字符串
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -3113,7 +3192,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
if (hex.length() == 1) sb.append('0'); // 补0 if (hex.length() == 1) sb.append('0'); // 补0
sb.append(hex); sb.append(hex);
} }
return sb.append("abc").toString(); return sb.toString();
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5算法不可用", e); throw new RuntimeException("MD5算法不可用", e);

View File

@@ -625,6 +625,10 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
for (MannequinDTO mannequin : designDTO.getMannequins()) { for (MannequinDTO mannequin : designDTO.getMannequins()) {
if (mannequin.getType().equals("System")) { if (mannequin.getType().equals("System")) {
SysFileVO byId = sysFileService.getById(mannequin.getId()); SysFileVO byId = sysFileService.getById(mannequin.getId());
if (Objects.isNull(byId)){
log.info("未知模特:{}{}", mannequin.getId(), "System");
throw new BusinessException("model.not.found");
}
// if (!StringUtils.isEmpty(byId.getLevel3Type()) && byId.getLevel2Type().equals("Female")) { // if (!StringUtils.isEmpty(byId.getLevel3Type()) && byId.getLevel2Type().equals("Female")) {
// elementVO.setStyle(byId.getLevel3Type()); // elementVO.setStyle(byId.getLevel3Type());
// } // }
@@ -645,7 +649,7 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, byId.getHigh(), byId.getWidth(), byId.getUrl())); elementVO.setDesignLibraryModelPoint(calculateTemplatePointTemplate(modelPoint, byId.getHigh(), byId.getWidth(), byId.getUrl()));
} else if (designDTO.getModelType().equals(ModelType.SYSTEM.getValue())) { } else if (designDTO.getModelType().equals(ModelType.SYSTEM.getValue())) {
SysFileVO byId = sysFileService.getById(designDTO.getTemplateId()); SysFileVO byId = sysFileService.getById(designDTO.getTemplateId());
if (!StringUtils.isEmpty(byId.getLevel3Type()) && byId.getLevel2Type().equals("Female")) { if (Objects.nonNull(byId) && !StringUtils.isEmpty(byId.getLevel3Type()) && byId.getLevel2Type().equals("Female")) {
elementVO.setStyle(byId.getLevel3Type()); elementVO.setStyle(byId.getLevel3Type());
} }
LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType()); LibraryModelPoint modelPoint = libraryModelPointService.getByRelationId(byId.getId(), designDTO.getModelType());

View File

@@ -178,7 +178,11 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
} }
} }
SysFileVO sysFileVO = sysFileService.getById(idValue); SysFileVO sysFileVO = sysFileService.getById(idValue);
return new GetNextSysElementVO(sysFileVO.getId(), level2Type, sysFileVO.getUrl()); if (Objects.nonNull(sysFileVO)){
return new GetNextSysElementVO(sysFileVO.getId(), level2Type, sysFileVO.getUrl());
}else {
return new GetNextSysElementVO();
}
} }
@Override @Override

View File

@@ -1846,11 +1846,17 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
// 所有修改的图片都另存为,不覆盖原图 // 所有修改的图片都另存为,不覆盖原图
if (proportionDTO.getType().equals("Library")) { if (proportionDTO.getType().equals("Library")) {
model = libraryService.getById(proportionDTO.getId()); model = libraryService.getById(proportionDTO.getId());
if (Objects.isNull(model)){
throw new BusinessException("model.not.found");
}
String url = model.getUrl(); String url = model.getUrl();
name = url.substring(url.indexOf("/") + 1, url.lastIndexOf("/")) + "/" + uuid; name = url.substring(url.indexOf("/") + 1, url.lastIndexOf("/")) + "/" + uuid;
// gender = model.getLevel2Type(); // gender = model.getLevel2Type();
} else { } else {
SysFileVO sysModel = sysFileService.getById(proportionDTO.getId()); SysFileVO sysModel = sysFileService.getById(proportionDTO.getId());
if (Objects.isNull(sysModel)){
throw new BusinessException("model.not.found");
}
gender = sysModel.getLevel2Type(); gender = sysModel.getLevel2Type();
name = accountId + "/models/" + gender.toLowerCase() + "/" + uuid; name = accountId + "/models/" + gender.toLowerCase() + "/" + uuid;
} }

View File

@@ -214,9 +214,12 @@ public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> impl
SysFileVO sysFile = LocalCacheUtils.getSysFileCache(id); SysFileVO sysFile = LocalCacheUtils.getSysFileCache(id);
if (Objects.isNull(sysFile) || Objects.isNull(sysFile.getId())) { if (Objects.isNull(sysFile) || Objects.isNull(sysFile.getId())) {
sysFile = CopyUtil.copyObject(sysFileMapper.selectById(id), SysFileVO.class); sysFile = CopyUtil.copyObject(sysFileMapper.selectById(id), SysFileVO.class);
LocalCacheUtils.setSysFileCache(id, sysFile); if (Objects.nonNull(sysFile)){
LocalCacheUtils.setSysFileCache(id, sysFile);
return sysFile;
}
} }
return sysFile; return null;
} }
@Override @Override

View File

@@ -2642,7 +2642,7 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
CollectionElementRelModel collectionElementRelModel = new CollectionElementRelModel(); CollectionElementRelModel collectionElementRelModel = new CollectionElementRelModel();
collectionElementRelModel.setCollectionElementId(collectionElement.getId()); collectionElementRelModel.setCollectionElementId(collectionElement.getId());
collectionElementRelModel.setRelationId(dto.getId()); collectionElementRelModel.setRelationId(dto.getId());
collectionElementRelModel.setRelationType("System"); collectionElementRelModel.setRelationType("Library");
collectionElementRelModelMapper.insert(collectionElementRelModel); collectionElementRelModelMapper.insert(collectionElementRelModel);
} }

View File

@@ -158,6 +158,7 @@ this.promotion.code.is.invalid=This promotion code is invalid.
one.time.limit.per.customer=This code has already been redeemed. Promo codes are limited to one-time use per customer. one.time.limit.per.customer=This code has already been redeemed. Promo codes are limited to one-time use per customer.
element.already.exists=This element already exists in the public library element.already.exists=This element already exists in the public library
have.no.permission=Sorry, you don't have permission have.no.permission=Sorry, you don't have permission
permit.bulk.creation=The system permits bulk account creation exclusively when no sub-accounts exist.
# 可能会报异常 # 可能会报异常
# Informative: # Informative:

View File

@@ -154,6 +154,7 @@ this.promotion.code.is.invalid=该促销码无效。
one.time.limit.per.customer=该码已兑换。每个促销码每位用户仅限使用一次。 one.time.limit.per.customer=该码已兑换。每个促销码每位用户仅限使用一次。
element.already.exists=元素已存在于公共库中 element.already.exists=元素已存在于公共库中
have.no.permission=您没有权限 have.no.permission=您没有权限
permit.bulk.creation=系统仅当不存在任何子账号时,才允许批量创建账号。
# 可能会报异常 # 可能会报异常
# Informative: # Informative: