Browse Source

20260309 钱包余额导出优化

huangqizheng/feature-20260309142559-钱包退款
wangguorui 1 month ago
parent
commit
2322add37d
  1. 3
      src/main/java/com/example/demo/Export/ExportService.java
  2. 51
      src/main/java/com/example/demo/Export/ExportServiceImpl.java
  3. 31
      src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java
  4. 22
      src/main/java/com/example/demo/controller/coin/ExportController.java
  5. 16
      src/main/java/com/example/demo/domain/DTO/UserWalletDTO.java
  6. 10
      src/main/java/com/example/demo/domain/vo/cash/UserWalletVO.java
  7. 1
      src/main/java/com/example/demo/service/coin/ExportExcelService.java
  8. 27
      src/main/java/com/example/demo/service/listen/UserWalletListener.java
  9. 118
      src/main/java/com/example/demo/serviceImpl/coin/ExportExcelServiceImpl.java

3
src/main/java/com/example/demo/Export/ExportService.java

@ -39,4 +39,7 @@ public interface ExportService {
// 用户钱包明细导出 // 用户钱包明细导出
Result addExportUserWalletRecord(UserWalletRecordDTO dto); Result addExportUserWalletRecord(UserWalletRecordDTO dto);
// 用户钱包余额导出
Result addExportUserWallet(UserWalletDTO dto);
} }

51
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.example.demo.service.coin.AdminService;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
@ -149,11 +147,16 @@ public class ExportServiceImpl implements ExportService {
fundDTO.setUrl(""); fundDTO.setUrl("");
fundDTO.setFileName(generateFileName("资金明细", adminName, lang)); fundDTO.setFileName(generateFileName("资金明细", adminName, lang));
fundDTO.setDataNum(0); 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.getFileName(),
fundDTO.getDataNum() fundDTO.getDataNum()
); );
}else if (dto instanceof UserWalletRecordDTO UserWalletRecordDTO){
}else if (dto instanceof UserWalletRecordDTO userWalletRecordDTO){
goldDetailMapper.insertExportRecord( goldDetailMapper.insertExportRecord(
idHolder, idHolder,
account, 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 对象 // 都为空放一个空的 VO 对象
requestData.put("userWalletRecordVO", new com.example.demo.domain.vo.cash.UserWalletRecordVO()); requestData.put("userWalletRecordVO", new com.example.demo.domain.vo.cash.UserWalletRecordVO());
} }
}else if (dto instanceof UserWalletDTO userWalletDTO){
// 特殊处理将查询参数放入 JSON
Map<String, Object> 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); 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()); 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());
}
} }

31
src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java

@ -629,6 +629,37 @@ public class ExcelHeaderTranslator {
} }
/** /**
* 获取用户钱包余额的 Excel 表头映射
* 返回 Map<字段名中文表头>
*/
public Map<String, String> getUserWalletBalanceHeaders(String lang) {
Map<String, String> 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<String> getUserWalletBalanceColumnOrder() {
return Arrays.asList(
"jwcode", "userName", "marketName", "walletName", "currentPermanentGold"
);
}
/**
* 翻译表头 * 翻译表头
*/ */
private Map<String, String> translateHeaders(Map<String, String> headers, String lang) { private Map<String, String> translateHeaders(Map<String, String> headers, String lang) {

22
src/main/java/com/example/demo/controller/coin/ExportController.java

@ -327,4 +327,26 @@ public class ExportController {
redisLockUtil.unlock(lockKey, requestId); 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);
}
}
} }

16
src/main/java/com/example/demo/domain/DTO/UserWalletDTO.java

@ -1,11 +1,9 @@
package com.example.demo.domain.DTO; 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 jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
// 用户钱包明细导出
// 用户钱包余额导出
@Data @Data
public class UserWalletDTO { public class UserWalletDTO {
private String token; private String token;
@ -14,17 +12,19 @@ public class UserWalletDTO {
private Integer sort = 0; private Integer sort = 0;
private String field = ""; private String field = "";
private Integer account; private Integer account;
private Integer type = 16; //类型
private Integer type = 17; //类型
private Integer state = 0; //状态 private Integer state = 0; //状态
private String text = ""; //关键词搜索 private String text = ""; //关键词搜索
private Integer dataNum = 0; private Integer dataNum = 0;
private String deptid = ""; private String deptid = "";
private String lang; 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; private Integer page = 1;
@NotNull(message = "pageSize不能为空")
@NotNull(message = "pageSize 不能为空")
private Integer pageSize = 20; private Integer pageSize = 20;
} }

10
src/main/java/com/example/demo/domain/vo/cash/UserWalletVO.java

@ -1,5 +1,6 @@
package com.example.demo.domain.vo.cash; package com.example.demo.domain.vo.cash;
import com.alibaba.excel.annotation.ExcelIgnore;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -14,8 +15,15 @@ import java.util.List;
public class UserWalletVO { public class UserWalletVO {
private Integer jwcode; // 精网号 private Integer jwcode; // 精网号
private String userName; // 用户名 private String userName; // 用户名
@ExcelIgnore
private String market; // 地区代码 private String market; // 地区代码
private String marketName; // 地区名称 private String marketName; // 地区名称
private List<WalletItem> walletList; // 钱包列表
// 用于扁平化导出的字段
@ExcelIgnore
private Integer walletId; // 钱包 ID
private String walletName; // 钱包名称
private BigDecimal currentPermanentGold; // 当前永久金币数量
private List<WalletItem> walletList; // 钱包列表仅用于查询结果
} }

1
src/main/java/com/example/demo/service/coin/ExportExcelService.java

@ -28,6 +28,7 @@ public interface ExportExcelService {
Exception ArticleExcel(String message) throws Exception; Exception ArticleExcel(String message) throws Exception;
Exception PerformanceExcel(String message) throws Exception; Exception PerformanceExcel(String message) throws Exception;
Exception UserWalletRecordExcel(String message) throws Exception; Exception UserWalletRecordExcel(String message) throws Exception;
Exception UserWalletExcel(String message) throws Exception;
List<Export> getExcel(Export export); List<Export> getExcel(Export export);
Exception BeanExcel(String message) throws Exception; Exception BeanExcel(String message) throws Exception;

27
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<String>{
@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);
}
}
}

118
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.ExportMapper;
import com.example.demo.mapper.coin.MarketMapper; 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.ExportExcelService;
import com.example.demo.service.coin.MarketService; import com.example.demo.service.coin.MarketService;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@ -91,6 +92,8 @@ public class ExportExcelServiceImpl implements ExportExcelService {
private ExportMapper exportMapper; private ExportMapper exportMapper;
@Autowired @Autowired
private MarketService marketService; private MarketService marketService;
@Autowired
private CashCollectionService cashCollectionService;
@Transactional @Transactional
@Override @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<UserWalletVO> result = cashCollectionService.selectUserWallets(jwcode, market, pageNum, pageSize);
// 翻译处理并将数据扁平化一个用户多个钱包要拆分成多行
List<UserWalletVO> flatList = new ArrayList<>();
if (result != null && result.getList() != null) {
translateUserWalletList((List<UserWalletVO>) 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 @Override
public List<Export> getExcel(Export export) { public List<Export> getExcel(Export export) {
List<Export> list = exportMapper.getExportRecord(export.getAccount(),export.getType()); List<Export> list = exportMapper.getExportRecord(export.getAccount(),export.getType());
@ -897,6 +968,26 @@ public class ExportExcelServiceImpl implements ExportExcelService {
.head(head) .head(head)
.build(); .build();
} }
// 如果是用户钱包余额表添加动态表头处理器
else if ("userWallet".equals(exportType)) {
Map<String, String> headers = excelHeaderTranslator.getUserWalletBalanceHeaders(lang);
List<String> columnOrder = excelHeaderTranslator.getUserWalletBalanceColumnOrder();
// 构建自定义表头
List<List<String>> head = new ArrayList<>();
for (String fieldName : columnOrder) {
String headerText = headers.get(fieldName);
if (headerText != null) {
List<String> headItems = new ArrayList<>();
headItems.add(headerText);
head.add(headItems);
}
}
writeSheet = EasyExcel.writerSheet("Sheet1")
.head(head)
.build();
}
else { else {
writeSheet = EasyExcel.writerSheet("Sheet1").build(); writeSheet = EasyExcel.writerSheet("Sheet1").build();
} }
@ -1171,6 +1262,8 @@ public class ExportExcelServiceImpl implements ExportExcelService {
return FundsDTO.class; return FundsDTO.class;
case "userWalletRecord": case "userWalletRecord":
return UserWalletRecordVO.class; return UserWalletRecordVO.class;
case "userWallet":
return UserWalletVO.class;
default: default:
throw new IllegalArgumentException("不支持的导出类型: " + exportType); throw new IllegalArgumentException("不支持的导出类型: " + exportType);
} }
@ -1944,4 +2037,29 @@ public class ExportExcelServiceImpl implements ExportExcelService {
} }
} }
} }
/**
* 翻译用户钱包列表
*/
private void translateUserWalletList(List<UserWalletVO> 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));
}
}
}
}
}
} }
Loading…
Cancel
Save