diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 77656d6a..5dceae65 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -369,6 +369,12 @@ public class AccountController { accountService.subAccountImportExcelDownload(response); } + @GetMapping("/exportAccountsToExcel") + @ApiOperation(value = "下载子账号信息") + public void exportAccountsToExcel(HttpServletResponse response) { + accountService.exportAccountsToExcel(response); + } + @PostMapping("/subAccountImport") @ApiOperation(value = "模板导入") public Response subAccountImport(@RequestParam("file") MultipartFile file) { diff --git a/src/main/java/com/ai/da/model/vo/GetNextSysElementVO.java b/src/main/java/com/ai/da/model/vo/GetNextSysElementVO.java index fea519db..12dd8e70 100644 --- a/src/main/java/com/ai/da/model/vo/GetNextSysElementVO.java +++ b/src/main/java/com/ai/da/model/vo/GetNextSysElementVO.java @@ -19,4 +19,6 @@ public class GetNextSysElementVO { @ApiModelProperty("对应的图片的绝对路径") private String path; + public GetNextSysElementVO() { + } } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index b1f9692d..ce6b6989 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -233,6 +233,8 @@ public interface AccountService extends IService { void subAccountImportExcelDownload(HttpServletResponse response); + void exportAccountsToExcel(HttpServletResponse response); + Boolean subAccountImport(MultipartFile file); Set organizationNameSearch(String type, String name); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index e172c3db..691fa8ec 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -39,6 +39,8 @@ import com.zaxxer.hikari.HikariDataSource; import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; 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.core.io.ClassPathResource; import org.springframework.stereotype.Service; @@ -2162,7 +2164,7 @@ public class AccountServiceImpl extends ServiceImpl impl int subUserRole = getSubUserRole(account.getSystemUser()); if (addSubAccountDTO.getId() == null) { - return createSubAccount(addSubAccountDTO, account, subUserRole, null, null); + return createSubAccount(addSubAccountDTO, account, subUserRole, addSubAccountDTO.getCreditsUsageLimit(), null); } else { return updateSubAccount(addSubAccountDTO, account, subUserRole); } @@ -3056,6 +3058,88 @@ public class AccountServiceImpl extends ServiceImpl impl } } + @Override + public void exportAccountsToExcel(HttpServletResponse response) { + Workbook workbook = null; + try { + // 1. 查询数据 + Account adminAcc = baseMapper.selectById(UserContext.getUserHolder().getId()); + List accounts = accountMapper.selectList(new QueryWrapper() + .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 public Boolean subAccountImport(MultipartFile file) { AuthPrincipalVo vo = UserContext.getUserHolder(); @@ -3069,29 +3153,24 @@ public class AccountServiceImpl extends ServiceImpl impl // 示例:打印或保存 for (SubAccountImportDTO dto : importList) { + // 只有当前子账号数量为0时允许批量上传 + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(Account::getSystemUser, 8) + .eq(Account::getOrganizationName, parent.getOrganizationName()); + List 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(); - account.setUserName(dto.getName()); - account.setUserEmail(dto.getEmail()); - account.setUserPassword(md5(dto.getPassword() + "abc")); - account.setCreditsUsageLimit(BigDecimal.valueOf(dto.getCredisUsageLimit())); - account.setParentId(vo.getId()); - 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); + AddSubAccountDTO addSubAccountDTO = new AddSubAccountDTO(); + addSubAccountDTO.setUserEmail(dto.getEmail()); + addSubAccountDTO.setUserName(dto.getEmail().substring(0, dto.getEmail().indexOf("@"))); + addSubAccountDTO.setUserPassword(md5(parent.getOrganizationName().toLowerCase() + "abc")); + // 添加用户 + addSubAccount(addSubAccountDTO); } return true; @@ -3104,7 +3183,7 @@ public class AccountServiceImpl extends ServiceImpl impl public static String md5(String input) { try { MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] messageDigest = md.digest(input.getBytes()); + byte[] messageDigest = md.digest(input.getBytes(StandardCharsets.UTF_8)); // 转为16进制字符串 StringBuilder sb = new StringBuilder(); @@ -3113,7 +3192,7 @@ public class AccountServiceImpl extends ServiceImpl impl if (hex.length() == 1) sb.append('0'); // 补0 sb.append(hex); } - return sb.append("abc").toString(); + return sb.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("MD5算法不可用", e); diff --git a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java index be628868..c4b1ba51 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java @@ -625,6 +625,10 @@ public class CollectionElementServiceImpl extends ServiceImpl i // 所有修改的图片都另存为,不覆盖原图 if (proportionDTO.getType().equals("Library")) { model = libraryService.getById(proportionDTO.getId()); + if (Objects.isNull(model)){ + throw new BusinessException("model.not.found"); + } String url = model.getUrl(); name = url.substring(url.indexOf("/") + 1, url.lastIndexOf("/")) + "/" + uuid; // gender = model.getLevel2Type(); } else { SysFileVO sysModel = sysFileService.getById(proportionDTO.getId()); + if (Objects.isNull(sysModel)){ + throw new BusinessException("model.not.found"); + } gender = sysModel.getLevel2Type(); name = accountId + "/models/" + gender.toLowerCase() + "/" + uuid; } diff --git a/src/main/java/com/ai/da/service/impl/SysFileServiceImpl.java b/src/main/java/com/ai/da/service/impl/SysFileServiceImpl.java index 67b20710..81c0fca6 100644 --- a/src/main/java/com/ai/da/service/impl/SysFileServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/SysFileServiceImpl.java @@ -214,9 +214,12 @@ public class SysFileServiceImpl extends ServiceImpl impl SysFileVO sysFile = LocalCacheUtils.getSysFileCache(id); if (Objects.isNull(sysFile) || Objects.isNull(sysFile.getId())) { 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 diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index 05a42a5c..037dafaf 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -2642,7 +2642,7 @@ public class UserLikeGroupServiceImpl extends ServiceImpl