diff --git a/src/main/java/com/example/demo/Export/ExportService.java b/src/main/java/com/example/demo/Export/ExportService.java index c1a025c..6c4d388 100644 --- a/src/main/java/com/example/demo/Export/ExportService.java +++ b/src/main/java/com/example/demo/Export/ExportService.java @@ -39,4 +39,7 @@ public interface ExportService { // 用户钱包明细导出 Result addExportUserWalletRecord(UserWalletRecordDTO dto); + + // 用户钱包余额导出 + Result addExportUserWallet(UserWalletDTO dto); } diff --git a/src/main/java/com/example/demo/Export/ExportServiceImpl.java b/src/main/java/com/example/demo/Export/ExportServiceImpl.java index b5291d4..857e770 100644 --- a/src/main/java/com/example/demo/Export/ExportServiceImpl.java +++ b/src/main/java/com/example/demo/Export/ExportServiceImpl.java @@ -11,9 +11,7 @@ import com.example.demo.Util.RedisUtil; import com.example.demo.service.coin.AdminService; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -149,11 +147,16 @@ public class ExportServiceImpl implements ExportService { fundDTO.setUrl(""); fundDTO.setFileName(generateFileName("资金明细", adminName, lang)); fundDTO.setDataNum(0); - } else if(dto instanceof UserWalletRecordDTO UserWalletRecordDTO){ - UserWalletRecordDTO.setAccount(Integer.valueOf(account)); - UserWalletRecordDTO.setUrl(""); - UserWalletRecordDTO.setFileName(generateFileName("用户钱包明细", adminName, lang)); - UserWalletRecordDTO.setDataNum(0); + } else if(dto instanceof UserWalletRecordDTO userWalletRecordDTO){ + userWalletRecordDTO.setAccount(Integer.valueOf(account)); + userWalletRecordDTO.setUrl(""); + userWalletRecordDTO.setFileName(generateFileName("用户钱包明细", adminName, lang)); + userWalletRecordDTO.setDataNum(0); + } else if (dto instanceof UserWalletDTO userWalletDTO) { + userWalletDTO.setAccount(Integer.valueOf(account)); + userWalletDTO.setUrl(""); + userWalletDTO.setFileName(generateFileName("用户钱包余额", adminName, lang)); + userWalletDTO.setDataNum(0); } } @@ -281,15 +284,25 @@ public class ExportServiceImpl implements ExportService { fundDTO.getFileName(), fundDTO.getDataNum() ); - }else if (dto instanceof UserWalletRecordDTO UserWalletRecordDTO){ + }else if (dto instanceof UserWalletRecordDTO userWalletRecordDTO){ goldDetailMapper.insertExportRecord( idHolder, account, - UserWalletRecordDTO.getType(), - UserWalletRecordDTO.getState(), - UserWalletRecordDTO.getUrl(), - UserWalletRecordDTO.getFileName(), - UserWalletRecordDTO.getDataNum() + userWalletRecordDTO.getType(), + userWalletRecordDTO.getState(), + userWalletRecordDTO.getUrl(), + userWalletRecordDTO.getFileName(), + userWalletRecordDTO.getDataNum() + ); + }else if (dto instanceof UserWalletDTO userWalletDTO){ + goldDetailMapper.insertExportRecord( + idHolder, + account, + userWalletDTO.getType(), + userWalletDTO.getState(), + userWalletDTO.getUrl(), + userWalletDTO.getFileName(), + userWalletDTO.getDataNum() ); } } @@ -343,6 +356,14 @@ public class ExportServiceImpl implements ExportService { // 都为空,放一个空的 VO 对象 requestData.put("userWalletRecordVO", new com.example.demo.domain.vo.cash.UserWalletRecordVO()); } + }else if (dto instanceof UserWalletDTO userWalletDTO){ + // 特殊处理:将查询参数放入 JSON + Map queryParams = new HashMap<>(); + queryParams.put("jwcode", userWalletDTO.getJwcode()); + queryParams.put("market", userWalletDTO.getMarket()); + queryParams.put("page", userWalletDTO.getPage()); + queryParams.put("pageSize", userWalletDTO.getPageSize()); + requestData.put(requestDataKey, queryParams); } exportData.put("requestData", requestData); @@ -426,4 +447,8 @@ public class ExportServiceImpl implements ExportService { return addExport(dto, "用户钱包明细", "user_wallet_record:queue:export_queue", "userWalletRecordVO", dto.getLang()); } + @Override + public Result addExportUserWallet(UserWalletDTO dto) { + return addExport(dto, "用户钱包余额", "user_wallet:queue:export_queue", "userWalletDTO", dto.getLang()); + } } diff --git a/src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java b/src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java index af336f4..1a34184 100644 --- a/src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java +++ b/src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java @@ -629,6 +629,37 @@ public class ExcelHeaderTranslator { } /** + * 获取用户钱包余额的 Excel 表头映射 + * 返回 Map<字段名,中文表头> + */ + public Map getUserWalletBalanceHeaders(String lang) { + Map headers = new LinkedHashMap<>(); + + // 定义所有表头的原始中文名称(对应 UserWalletVO 类的字段) + headers.put("jwcode", "精网号"); + headers.put("userName", "姓名"); + headers.put("marketName", "所属地区"); + headers.put("walletName", "钱包名称"); + headers.put("currentPermanentGold", "当前永久金币"); + + // 如果需要翻译,则翻译表头 + if (!isChineseLanguage(lang)) { + return translateHeaders(headers, lang); + } + + return headers; + } + + /** + * 获取用户钱包余额表头顺序 + */ + public List getUserWalletBalanceColumnOrder() { + return Arrays.asList( + "jwcode", "userName", "marketName", "walletName", "currentPermanentGold" + ); + } + + /** * 翻译表头 */ private Map translateHeaders(Map headers, String lang) { diff --git a/src/main/java/com/example/demo/controller/coin/ExportController.java b/src/main/java/com/example/demo/controller/coin/ExportController.java index 6e9b1b2..205cbf9 100644 --- a/src/main/java/com/example/demo/controller/coin/ExportController.java +++ b/src/main/java/com/example/demo/controller/coin/ExportController.java @@ -327,4 +327,26 @@ public class ExportController { redisLockUtil.unlock(lockKey, requestId); } } + + /** + * 用户钱包余额导出 + */ + @PostMapping("/exportUserWallet") + public Result exportUserWallet(@Valid @RequestBody UserWalletDTO dto, @RequestHeader(defaultValue = "zh_CN") String lang) { + String lockKey = "export:lock:" + dto.getToken(); + String requestId = UUID.randomUUID().toString(); + long expireTime = 5000; + dto.setLang(lang);// 设置语言参数 + try { + // 尝试获取锁 + if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { + throw new BusinessException("操作太频繁,请稍后重试"); + } + // 执行业务逻辑 + return exportService.addExportUserWallet(dto); + } finally { + // 释放锁 + redisLockUtil.unlock(lockKey, requestId); + } + } } \ No newline at end of file diff --git a/src/main/java/com/example/demo/domain/DTO/UserWalletDTO.java b/src/main/java/com/example/demo/domain/DTO/UserWalletDTO.java index 84166a9..ebd1d09 100644 --- a/src/main/java/com/example/demo/domain/DTO/UserWalletDTO.java +++ b/src/main/java/com/example/demo/domain/DTO/UserWalletDTO.java @@ -1,11 +1,9 @@ package com.example.demo.domain.DTO; -import com.example.demo.domain.entity.UserWalletRecord; -import com.example.demo.domain.vo.cash.UserWalletRecordVO; import jakarta.validation.constraints.NotNull; import lombok.Data; -// 用户钱包明细导出 +// 用户钱包余额导出 @Data public class UserWalletDTO { private String token; @@ -14,17 +12,19 @@ public class UserWalletDTO { private Integer sort = 0; private String field = ""; private Integer account; - private Integer type = 16; //类型 + private Integer type = 17; //类型 private Integer state = 0; //状态 private String text = ""; //关键词搜索 private Integer dataNum = 0; private String deptid = ""; private String lang; - private UserWalletRecordVO userWalletRecordVO; - private UserWalletRecord userWalletRecord; - @NotNull(message = "page不能为空") + // 查询条件字段 + private Integer jwcode; + private String market; + + @NotNull(message = "page 不能为空") private Integer page = 1; - @NotNull(message = "pageSize不能为空") + @NotNull(message = "pageSize 不能为空") private Integer pageSize = 20; } diff --git a/src/main/java/com/example/demo/domain/vo/cash/UserWalletVO.java b/src/main/java/com/example/demo/domain/vo/cash/UserWalletVO.java index e0fe6eb..91b9e71 100644 --- a/src/main/java/com/example/demo/domain/vo/cash/UserWalletVO.java +++ b/src/main/java/com/example/demo/domain/vo/cash/UserWalletVO.java @@ -1,5 +1,6 @@ package com.example.demo.domain.vo.cash; +import com.alibaba.excel.annotation.ExcelIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -14,8 +15,15 @@ import java.util.List; public class UserWalletVO { private Integer jwcode; // 精网号 private String userName; // 用户名 + @ExcelIgnore private String market; // 地区代码 private String marketName; // 地区名称 - private List walletList; // 钱包列表 + // 用于扁平化导出的字段 + @ExcelIgnore + private Integer walletId; // 钱包 ID + private String walletName; // 钱包名称 + private BigDecimal currentPermanentGold; // 当前永久金币数量 + + private List walletList; // 钱包列表(仅用于查询结果) } diff --git a/src/main/java/com/example/demo/service/coin/ExportExcelService.java b/src/main/java/com/example/demo/service/coin/ExportExcelService.java index b09081a..35e7d3c 100644 --- a/src/main/java/com/example/demo/service/coin/ExportExcelService.java +++ b/src/main/java/com/example/demo/service/coin/ExportExcelService.java @@ -28,6 +28,7 @@ public interface ExportExcelService { Exception ArticleExcel(String message) throws Exception; Exception PerformanceExcel(String message) throws Exception; Exception UserWalletRecordExcel(String message) throws Exception; + Exception UserWalletExcel(String message) throws Exception; List getExcel(Export export); Exception BeanExcel(String message) throws Exception; diff --git a/src/main/java/com/example/demo/service/listen/UserWalletListener.java b/src/main/java/com/example/demo/service/listen/UserWalletListener.java new file mode 100644 index 0000000..d9a4f6f --- /dev/null +++ b/src/main/java/com/example/demo/service/listen/UserWalletListener.java @@ -0,0 +1,27 @@ +package com.example.demo.service.listen; + +import com.example.demo.Util.RedisUtil; +import com.example.demo.service.coin.ExportExcelService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class UserWalletListener extends BaseMessageListener{ + @Autowired + private ExportExcelService exportExcelService; + + protected UserWalletListener(RedisUtil redisQueueUtil) { + super(redisQueueUtil,"user_wallet:queue:export_queue"); + } + + @Override + protected void handleMessage(String message) { + validateMessage( message); + try { + Thread.sleep(5000); + exportExcelService.UserWalletExcel(message); + } catch (Exception e) { + handleException(e, message); + } + } +} diff --git a/src/main/java/com/example/demo/serviceImpl/coin/ExportExcelServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/coin/ExportExcelServiceImpl.java index d927139..e7c7059 100644 --- a/src/main/java/com/example/demo/serviceImpl/coin/ExportExcelServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/coin/ExportExcelServiceImpl.java @@ -28,6 +28,7 @@ import com.example.demo.domain.vo.coin.*; import com.example.demo.mapper.coin.ExportMapper; import com.example.demo.mapper.coin.MarketMapper; +import com.example.demo.service.cash.CashCollectionService; import com.example.demo.service.coin.ExportExcelService; import com.example.demo.service.coin.MarketService; import com.fasterxml.jackson.databind.JsonNode; @@ -91,6 +92,8 @@ public class ExportExcelServiceImpl implements ExportExcelService { private ExportMapper exportMapper; @Autowired private MarketService marketService; + @Autowired + private CashCollectionService cashCollectionService; @Transactional @Override @@ -527,6 +530,74 @@ public class ExportExcelServiceImpl implements ExportExcelService { }); } + @Transactional + @Override + public Exception UserWalletExcel(String message) throws Exception { + return exportExcelGeneric(message, "userWallet", page -> { + try { + JsonNode rootNode = objectMapper.readTree(message); + JsonNode requestDataNode = rootNode.path("requestData"); + JsonNode userWalletDTONode = requestDataNode.path("userWalletDTO"); + + // 解析查询参数 + Integer jwcode = null; + String market = null; + Integer pageNum = userWalletDTONode.path("page").asInt(1); + Integer pageSize = userWalletDTONode.path("pageSize").asInt(20); + + if (!userWalletDTONode.path("jwcode").isMissingNode()) { + jwcode = userWalletDTONode.path("jwcode").asInt(); + } + if (!userWalletDTONode.path("market").isMissingNode()) { + market = userWalletDTONode.path("market").asText(); + } + + // 从请求数据中获取语言设置 + String lang = "zh_CN"; + JsonNode langNode = rootNode.path("lang"); + if (langNode != null && !langNode.asText().isEmpty()) { + lang = langNode.asText(); + } + + // 调用查询接口 + PageInfo result = cashCollectionService.selectUserWallets(jwcode, market, pageNum, pageSize); + + // 翻译处理并将数据扁平化(一个用户多个钱包要拆分成多行) + List flatList = new ArrayList<>(); + if (result != null && result.getList() != null) { + translateUserWalletList((List) result.getList(), lang); + + // 将嵌套结构转换为扁平列表(每个钱包作为一行) + for (UserWalletVO vo : result.getList()) { + if (vo.getWalletList() != null && !vo.getWalletList().isEmpty()) { + // 为每个钱包创建一个独立的 UserWalletVO 对象 + for (WalletItem wallet : vo.getWalletList()) { + UserWalletVO flatVO = new UserWalletVO(); + flatVO.setJwcode(vo.getJwcode()); + flatVO.setUserName(vo.getUserName()); + flatVO.setMarketName(vo.getMarketName()); + flatVO.setWalletId(wallet.getWalletId()); + flatVO.setWalletName(wallet.getWalletName()); + flatVO.setCurrentPermanentGold(wallet.getCurrentPermanentGold()); + flatList.add(flatVO); + } + } else { + // 如果没有钱包,也保留该用户记录 + flatList.add(vo); + } + } + + // 更新分页信息的 list 为扁平化后的列表 + result.setList(flatList); + } + + return Result.success(result); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + @Override public List getExcel(Export export) { List list = exportMapper.getExportRecord(export.getAccount(),export.getType()); @@ -897,6 +968,26 @@ public class ExportExcelServiceImpl implements ExportExcelService { .head(head) .build(); } + // 如果是用户钱包余额表,添加动态表头处理器 + else if ("userWallet".equals(exportType)) { + Map headers = excelHeaderTranslator.getUserWalletBalanceHeaders(lang); + List columnOrder = excelHeaderTranslator.getUserWalletBalanceColumnOrder(); + + // 构建自定义表头 + List> head = new ArrayList<>(); + for (String fieldName : columnOrder) { + String headerText = headers.get(fieldName); + if (headerText != null) { + List headItems = new ArrayList<>(); + headItems.add(headerText); + head.add(headItems); + } + } + + writeSheet = EasyExcel.writerSheet("Sheet1") + .head(head) + .build(); + } else { writeSheet = EasyExcel.writerSheet("Sheet1").build(); } @@ -1171,6 +1262,8 @@ public class ExportExcelServiceImpl implements ExportExcelService { return FundsDTO.class; case "userWalletRecord": return UserWalletRecordVO.class; + case "userWallet": + return UserWalletVO.class; default: throw new IllegalArgumentException("不支持的导出类型: " + exportType); } @@ -1944,4 +2037,29 @@ public class ExportExcelServiceImpl implements ExportExcelService { } } } + /** + * 翻译用户钱包列表 + */ + private void translateUserWalletList(List list, String lang) { + if (list == null || list.isEmpty() || "zh_CN".equalsIgnoreCase(lang) || "zh".equalsIgnoreCase(lang)) { + return; + } + + for (UserWalletVO item : list) { + // 翻译地区名称 + if (item.getMarketName() != null && !item.getMarketName().isEmpty()) { + item.setMarketName(languageTranslationUtil.translate(item.getMarketName(), lang)); + } + + // 翻译钱包名称 + if (item.getWalletList() != null) { + for (WalletItem wallet : item.getWalletList()) { + if (wallet.getWalletName() != null && !wallet.getWalletName().isEmpty()) { + wallet.setWalletName(languageTranslationUtil.translate(wallet.getWalletName(), lang)); + } + } + } + } + } + }