Merge remote-tracking branch 'origin/master'

This commit is contained in:
zjf committed 2026-08-18 18:13:32 +08:00
commit 96f495d555
5 files changed
+430 -107

No files matched your search

@@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.asynctask.vo.AsyncTaskProgressVO;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.log.annotation.SysLog;
@@ -24,8 +25,8 @@ import com.bsd.pjcloud.wallet.api.vo.WalletQbTotalVo;
import com.bsd.pjcloud.wallet.mapper.WalletManageMapper;
import com.bsd.pjcloud.wallet.mapper.mch.view.MchDeptViewMapper;
import com.bsd.pjcloud.wallet.service.WalletCodeUseService;
import com.bsd.pjcloud.wallet.service.WalletManageExportService;
import com.bsd.pjcloud.wallet.service.WalletManageService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springdoc.core.annotations.ParameterObject;
@@ -50,6 +51,9 @@ public class WalletManageController {
private final WalletManageService walletManageService;
private final WalletCodeUseService walletCodeUseService;
/** 钱包管理异步导出服务,负责提交任务并生成可轮询的文件结果。 */
private final WalletManageExportService walletManageExportService;
private final WalletManageMapper walletManageMapper;
private final MchDeptViewMapper mchDeptViewMapper;
@@ -358,15 +362,27 @@ public class WalletManageController {
return R.ok(walletManageService.removeBatchByIds(CollUtil.toList(ids)));
}
/**
* 按当前筛选条件提交账户余额异步导出任务。
*
* @param dto 账户余额筛选条件
* @return 供前端轮询的初始进度,成功终态包含文件下载地址
*/
@PostMapping("/export")
@PreAuthorize("@pms.hasPermission('wallet_walletManage_export')")
public void export(HttpServletResponse response, @ParameterObject Page page, @RequestBody WalletManageDto dto) {
walletManageService.export(response, page, dto);
public R<AsyncTaskProgressVO> export(@RequestBody WalletManageDto dto) {
return R.ok(walletManageExportService.submitExport(dto), "账户余额导出任务已提交");
}
/**
* 按当前筛选条件提交月度钱包记录异步导出任务。
*
* @param dto 月度钱包记录筛选条件
* @return 供前端轮询的初始进度,成功终态包含文件下载地址
*/
@PostMapping("/export-qb")
// @PreAuthorize("@pms.hasPermission('wallet_walletManage_export')")
public void exportQb(HttpServletResponse response, @ParameterObject Page page, @RequestBody WalletManageBalanceDto dto) {
walletManageService.exportQb(response, page, dto);
public R<AsyncTaskProgressVO> exportQb(@RequestBody WalletManageBalanceDto dto) {
return R.ok(walletManageExportService.submitQbExport(dto), "钱包记录导出任务已提交");
}
}
@@ -0,0 +1,28 @@
package com.bsd.pjcloud.wallet.service;
import com.bsd.pjcloud.common.asynctask.vo.AsyncTaskProgressVO;
import com.bsd.pjcloud.wallet.api.dto.WalletManageBalanceDto;
import com.bsd.pjcloud.wallet.api.dto.WalletManageDto;
/**
* 钱包管理导出服务。
* <p>导出任务统一异步执行,提交接口只返回任务进度,文件生成后由通用进度接口提供下载地址。</p>
*/
public interface WalletManageExportService {
/**
* 提交账户余额异步导出任务。
*
* @param dto 账户余额筛选条件;任务提交后会复制一份条件供后台线程独占使用
* @return 已创建的异步任务初始进度
*/
AsyncTaskProgressVO submitExport(WalletManageDto dto);
/**
* 提交月度钱包记录异步导出任务。
*
* @param dto 月度钱包记录筛选条件;任务提交后会复制一份条件供后台线程独占使用
* @return 已创建的异步任务初始进度
*/
AsyncTaskProgressVO submitQbExport(WalletManageBalanceDto dto);
}
@@ -12,7 +12,6 @@ import com.bsd.pjcloud.wallet.api.entity.WalletManageEntity;
import com.bsd.pjcloud.wallet.api.entity.mch.MchTakeOutSettingEntity;
import com.bsd.pjcloud.wallet.api.vo.WalletManageVo;
import com.bsd.pjcloud.wallet.api.vo.WalletQbTotalVo;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import java.util.List;
@@ -105,16 +104,6 @@ public interface WalletManageService extends IService<WalletManageEntity> {
*/
String getQrCode(Long walletId);
/**
* 导出
*/
void export(HttpServletResponse response, Page page, WalletManageDto dto);
/**
* 钱包记录导出
*/
void exportQb(HttpServletResponse response, Page page, WalletManageBalanceDto dto);
/**
* 修改用户
*/
@@ -0,0 +1,381 @@
package com.bsd.pjcloud.wallet.service.impl;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.bsd.pjcloud.admin.api.feign.RemoteFileService;
import com.bsd.pjcloud.common.asynctask.service.AsyncTaskExecutorService;
import com.bsd.pjcloud.common.asynctask.service.AsyncTaskProgressReporter;
import com.bsd.pjcloud.common.asynctask.service.AsyncTaskResult;
import com.bsd.pjcloud.common.asynctask.vo.AsyncTaskProgressVO;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
import com.bsd.pjcloud.common.data.datascope.DataScopeFuncEnum;
import com.bsd.pjcloud.wallet.api.dto.WalletManageBalanceDto;
import com.bsd.pjcloud.wallet.api.dto.WalletManageDto;
import com.bsd.pjcloud.wallet.api.vo.WalletManageVo;
import com.bsd.pjcloud.wallet.mapper.WalletManageMapper;
import com.bsd.pjcloud.wallet.service.WalletManageExportService;
import com.bsd.pjcloud.wallet.service.WalletManageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 钱包管理导出服务实现。
* <p>导出过程沿用系统用户导出的异步任务、进度上报和文件中心上传协议,避免 HTTP 请求长时间占用连接。</p>
*/
@Slf4j
@Service
public class WalletManageExportServiceImpl implements WalletManageExportService {
/** 账户余额导出任务的 Redis Key 命名空间。 */
private static final String BALANCE_EXPORT_REDIS_KEY = "wallet:manage:export:balance";
/** 钱包记录导出任务的 Redis Key 命名空间。 */
private static final String RECORD_EXPORT_REDIS_KEY = "wallet:manage:export:record";
/** 账户余额导出任务展示名称。 */
private static final String BALANCE_EXPORT_TASK_NAME = "账户余额导出";
/** 钱包记录导出任务展示名称。 */
private static final String RECORD_EXPORT_TASK_NAME = "钱包记录导出";
/** 查询真实数据量前创建任务使用的占位总数。 */
private static final int INITIAL_TOTAL = 1;
/** 账户余额导出的最大记录数,与原同步导出限制保持一致。 */
private static final int MAX_BALANCE_EXPORT_SIZE = 5000;
/** 账户余额导出模板路径。 */
private static final String BALANCE_TEMPLATE_PATH = "file/账户余额.xlsx";
/** 月度钱包记录导出模板路径。 */
private static final String RECORD_TEMPLATE_PATH = "file/个人钱包记录明细.xlsx";
/** 文件中心保存导出文件的业务目录。 */
private static final String EXPORT_FILE_DIR = "wallet-export";
/** 文件中心标记账户余额导出的类型编码。 */
private static final String BALANCE_EXPORT_FILE_TYPE = "WALLET_BALANCE_EXPORT";
/** 文件中心标记钱包记录导出的类型编码。 */
private static final String RECORD_EXPORT_FILE_TYPE = "WALLET_RECORD_EXPORT";
/** Excel 文件上传时使用的 MIME 类型。 */
private static final String EXCEL_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
/** 异步生成文件名使用的时间格式,避免连续导出文件名难以区分。 */
private static final DateTimeFormatter EXPORT_FILE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
/** 钱包查询服务,负责执行数据权限过滤、用户部门补充和钱包类型转换。 */
private final WalletManageService walletManageService;
/** 钱包 Mapper,用于在账户余额导出前按数据权限统计记录数。 */
private final WalletManageMapper walletManageMapper;
/** 通用异步任务执行器,负责恢复租户、安全和 Feign 上下文并持久化进度。 */
private final AsyncTaskExecutorService asyncTaskExecutorService;
/** 文件中心远程服务,用于保存异步生成的 Excel 文件。 */
private final RemoteFileService remoteFileService;
/**
* 创建钱包管理导出服务。
*
* @param walletManageService 钱包查询服务
* @param walletManageMapper 钱包数据 Mapper
* @param asyncTaskExecutorService 通用异步任务执行器
* @param remoteFileService 文件中心远程服务
*/
public WalletManageExportServiceImpl(WalletManageService walletManageService, WalletManageMapper walletManageMapper,
AsyncTaskExecutorService asyncTaskExecutorService, RemoteFileService remoteFileService) {
this.walletManageService = walletManageService;
this.walletManageMapper = walletManageMapper;
this.asyncTaskExecutorService = asyncTaskExecutorService;
this.remoteFileService = remoteFileService;
}
/**
* 提交账户余额异步导出任务。
*
* @param dto 账户余额筛选条件
* @return 已创建的异步任务初始进度
*/
@Override
public AsyncTaskProgressVO submitExport(WalletManageDto dto) {
WalletManageDto querySnapshot = copyWalletManageDto(dto);
return asyncTaskExecutorService.submitWithResult(BALANCE_EXPORT_REDIS_KEY, BALANCE_EXPORT_TASK_NAME,
INITIAL_TOTAL, reporter -> exportBalance(querySnapshot, reporter));
}
/**
* 提交月度钱包记录异步导出任务。
*
* @param dto 月度钱包记录筛选条件
* @return 已创建的异步任务初始进度
*/
@Override
public AsyncTaskProgressVO submitQbExport(WalletManageBalanceDto dto) {
WalletManageBalanceDto querySnapshot = copyBalanceDto(dto);
return asyncTaskExecutorService.submitWithResult(RECORD_EXPORT_REDIS_KEY, RECORD_EXPORT_TASK_NAME,
INITIAL_TOTAL, reporter -> exportWalletRecords(querySnapshot, reporter));
}
/**
* 查询、整理并上传账户余额导出文件。
*
* @param dto 后台线程独占的账户余额筛选条件
* @param reporter 当前异步任务进度报告器
* @return 文件中心下载地址和文件名
*/
private AsyncTaskResult exportBalance(WalletManageDto dto, AsyncTaskProgressReporter reporter) {
Long count = walletManageMapper.count(dto, DataScope.of().func(DataScopeFuncEnum.COUNT));
if (count == null || count == 0) {
throw new IllegalStateException("没有符合当前条件的账户余额");
}
if (count > MAX_BALANCE_EXPORT_SIZE) {
throw new IllegalStateException("导出数据超出5000条,请缩小查询范围");
}
List<WalletManageVo> list = walletManageService.scopeList(dto, DataScope.of());
if (ObjectUtil.isEmpty(list)) {
throw new IllegalStateException("没有符合当前条件的账户余额");
}
if (list.size() > MAX_BALANCE_EXPORT_SIZE) {
throw new IllegalStateException("导出数据超出5000条,请缩小查询范围");
}
reporter.updateTotal(list.size(), "已查询 " + list.size() + " 条账户余额");
Map<String, Object> summary = prepareBalanceRows(dto, list, reporter);
String fileName = "电子钱包_" + LocalDateTime.now().format(EXPORT_FILE_TIME_FORMATTER) + ".xlsx";
String fileUrl = writeAndUpload(BALANCE_TEMPLATE_PATH, summary, list, fileName, BALANCE_EXPORT_FILE_TYPE);
reporter.advance("账户余额导出文件已生成,共 " + list.size() + " 条");
return AsyncTaskResult.file(fileUrl, fileName);
}
/**
* 查询、整理并上传钱包记录导出文件。
*
* @param dto 后台线程独占的月度钱包记录筛选条件
* @param reporter 当前异步任务进度报告器
* @return 文件中心下载地址和文件名
*/
private AsyncTaskResult exportWalletRecords(WalletManageBalanceDto dto, AsyncTaskProgressReporter reporter) {
List<WalletManageVo> list = walletManageService.scopeQbList(dto, DataScope.of());
if (ObjectUtil.isEmpty(list)) {
throw new IllegalStateException("没有符合当前条件的钱包记录");
}
reporter.updateTotal(list.size(), "已查询 " + list.size() + " 条钱包记录");
Map<String, Object> summary = prepareRecordRows(list, reporter, dto.getWalletRecordMonth());
String fileName = "钱包记录_" + LocalDateTime.now().format(EXPORT_FILE_TIME_FORMATTER) + ".xlsx";
String fileUrl = writeAndUpload(RECORD_TEMPLATE_PATH, summary, list, fileName, RECORD_EXPORT_FILE_TYPE);
reporter.advance("钱包记录导出文件已生成,共 " + list.size() + " 条");
return AsyncTaskResult.file(fileUrl, fileName);
}
/**
* 为账户余额行补充序号、金额展示值并累计汇总金额。
*
* @param dto 账户余额筛选条件,用于填充模板中的查询时间范围
* @param list 待导出的账户余额列表
* @param reporter 当前异步任务进度报告器
* @return Excel 模板头部需要填充的汇总字段
*/
private Map<String, Object> prepareBalanceRows(WalletManageDto dto, List<WalletManageVo> list,
AsyncTaskProgressReporter reporter) {
Map<String, Object> summary = new HashMap<>();
if (ObjectUtil.isNotEmpty(dto.getCreateTimeList())) {
summary.put("timeSpan", " 到 ");
summary.put("startTime", LocalDateTimeUtil.format(dto.getCreateTimeList()[0], DatePattern.NORM_DATETIME_PATTERN));
summary.put("endTime", LocalDateTimeUtil.format(dto.getCreateTimeList()[1], DatePattern.NORM_DATETIME_PATTERN));
}
long balanceSum = 0;
long totalExpenseSum = 0;
long totalRechargeSum = 0;
for (int index = 0; index < list.size(); index++) {
WalletManageVo item = list.get(index);
item.setLineNumber((long) index + 1);
if (item.getBalance() != null) {
balanceSum += item.getBalance();
item.setBalanceStr(formatPrice(item.getBalance()));
}
if (item.getTotalExpense() != null) {
totalExpenseSum += item.getTotalExpense();
item.setTotalExpenseStr(formatPrice(item.getTotalExpense()));
}
if (item.getTotalRecharge() != null) {
totalRechargeSum += item.getTotalRecharge();
item.setTotalRechargeStr(formatPrice(item.getTotalRecharge()));
}
advanceExceptLast(reporter, index, list.size(), "正在整理第 " + (index + 1) + " / " + list.size() + " 条账户余额");
}
summary.put("balanceSum", formatPrice(balanceSum));
summary.put("totalExpenseSum", formatPrice(totalExpenseSum));
summary.put("totalRechargeSum", formatPrice(totalRechargeSum));
return summary;
}
/**
* 为钱包记录行补充序号、金额展示值并累计余额。
*
* @param list 待导出的钱包记录列表
* @param reporter 当前异步任务进度报告器
* @param walletRecordMonth 查询月份,写入模板头部
* @return Excel 模板头部需要填充的汇总字段
*/
private Map<String, Object> prepareRecordRows(List<WalletManageVo> list, AsyncTaskProgressReporter reporter,
String walletRecordMonth) {
Map<String, Object> summary = new HashMap<>();
long balanceSum = 0;
summary.put("walletRecordMonth", walletRecordMonth);
for (int index = 0; index < list.size(); index++) {
WalletManageVo item = list.get(index);
item.setLineNumber((long) index + 1);
if (item.getBalance() != null) {
balanceSum += item.getBalance();
item.setBalanceStr(formatPrice(item.getBalance()));
}
advanceExceptLast(reporter, index, list.size(), "正在整理第 " + (index + 1) + " / " + list.size() + " 条钱包记录");
}
summary.put("balanceSum", formatPrice(balanceSum));
return summary;
}
/**
* 在文件生成前报告除最后一条以外的行处理进度,最后一条在上传成功后报告,避免提前显示 100%。
*
* @param reporter 当前异步任务进度报告器
* @param index 当前行下标
* @param total 总行数
* @param message 当前处理说明
*/
private void advanceExceptLast(AsyncTaskProgressReporter reporter, int index, int total, String message) {
if (index < total - 1) {
reporter.advance(message);
}
}
/**
* 将分单位金额转换为模板展示使用的元字符串。
*
* @param amount 金额,单位分
* @return 两位小数的元金额字符串
*/
private String formatPrice(long amount) {
return BigDecimal.valueOf(amount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toPlainString();
}
/**
* 使用既有模板填充 Excel,并上传到文件中心。
*
* @param templatePath 类路径模板
* @param summary 模板头部汇总字段
* @param rows 模板明细行
* @param fileName 下载文件名
* @param fileType 文件中心分类编码
* @return 文件中心下载地址
*/
private String writeAndUpload(String templatePath, Map<String, Object> summary, List<WalletManageVo> rows,
String fileName, String fileType) {
try (InputStream template = ResourceUtil.getStream(templatePath); ByteArrayOutputStream output = new ByteArrayOutputStream()) {
try (ExcelWriter excelWriter = EasyExcel.write(output).withTemplate(template).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet().build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(summary, writeSheet);
excelWriter.fill(rows, fillConfig, writeSheet);
}
MultipartFile exportFile = new MockMultipartFile("file", encodeUploadOriginalFilename(fileName),
EXCEL_CONTENT_TYPE, output.toByteArray());
R uploadResult = remoteFileService.innerUpload(exportFile, EXPORT_FILE_DIR, null, fileType);
if (uploadResult == null || !uploadResult.isOk() || !(uploadResult.getData() instanceof Map<?, ?> resultData)) {
throw new IllegalStateException("文件中心未返回有效的钱包导出结果");
}
Object resultUrl = resultData.get("url");
if (resultUrl == null || StrUtil.isBlank(resultUrl.toString())) {
throw new IllegalStateException("文件中心未返回钱包导出下载地址");
}
return resultUrl.toString();
} catch (Exception exception) {
log.error("|钱包管理导出|生成或保存文件失败,fileName:{}", fileName, exception);
throw new IllegalStateException("生成钱包导出文件失败", exception);
}
}
/**
* 复制账户余额筛选条件,避免异步线程读取请求对象中的可变集合。
*
* @param source 控制器接收的筛选条件,可为空
* @return 后台线程独占的筛选条件副本
*/
private WalletManageDto copyWalletManageDto(WalletManageDto source) {
WalletManageDto target = new WalletManageDto();
if (source == null) {
return target;
}
BeanUtils.copyProperties(source, target);
target.setUserIds(copyList(source.getUserIds()));
target.setWalletIds(copyList(source.getWalletIds()));
target.setDeptIds(copyList(source.getDeptIds()));
target.setCreateTimeList(source.getCreateTimeList() == null ? null : source.getCreateTimeList().clone());
return target;
}
/**
* 复制钱包记录筛选条件,避免异步线程读取请求对象中的可变集合。
*
* @param source 控制器接收的筛选条件,可为空
* @return 后台线程独占的筛选条件副本
*/
private WalletManageBalanceDto copyBalanceDto(WalletManageBalanceDto source) {
WalletManageBalanceDto target = new WalletManageBalanceDto();
if (source == null) {
return target;
}
BeanUtils.copyProperties(source, target);
target.setUserIds(copyList(source.getUserIds()));
target.setDeptIds(copyList(source.getDeptIds()));
target.setScopeDeptIds(copyList(source.getScopeDeptIds()));
return target;
}
/**
* 复制可变筛选集合,空值保持空值语义。
*
* @param source 请求中的筛选集合
* @param <T> 集合元素类型
* @return 非空时返回新的列表
*/
private <T> List<T> copyList(List<T> source) {
return source == null ? null : new ArrayList<>(source);
}
/**
* 按文件服务约定编码中文原始文件名,避免文件中心的 ISO-8859-1 转 UTF-8 过程产生乱码。
*
* @param fileName 用户下载时看到的 UTF-8 文件名
* @return 交给文件中心上传接口的原始文件名
*/
private String encodeUploadOriginalFilename(String fileName) {
return new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
}
}
@@ -3,14 +3,8 @@ package com.bsd.pjcloud.wallet.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -52,7 +46,6 @@ import com.bsd.pjcloud.wallet.mapper.WalletTransactionMapper;
import com.bsd.pjcloud.wallet.mapper.WalletTypeMapper;
import com.bsd.pjcloud.wallet.mapper.mch.MchTakeOutSettingMapper;
import com.bsd.pjcloud.wallet.service.*;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -62,12 +55,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 钱包管理
@@ -466,85 +454,6 @@ public class WalletManageServiceImpl extends ServiceImpl<WalletManageMapper, Wal
return walletList;
}
@Override
public void export(HttpServletResponse response, Page page, WalletManageDto dto) {
String fileName = "file/账户余额.xlsx";
DataScope dataScope = DataScope.of();
Long count = baseMapper.count(dto, dataScope);
if (count > 5000) throw new RuntimeException("导出数据超出5000条,请缩小查询范围");
List<WalletManageVo> list = scopeList(dto, dataScope);
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(ResourceUtil.getStream(fileName)).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet().build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
Map<String, Object> map = new HashMap<String, Object>();
if (ObjectUtil.isNotEmpty(dto.getCreateTimeList())) {
map.put("timeSpan", " 到 ");
map.put("startTime", LocalDateTimeUtil.format(dto.getCreateTimeList()[0], DatePattern.NORM_DATETIME_PATTERN));
map.put("endTime", LocalDateTimeUtil.format(dto.getCreateTimeList()[1], DatePattern.NORM_DATETIME_PATTERN));
}
if (ObjectUtil.isNotEmpty(list)) {
BigDecimal balanceSum = BigDecimal.ZERO;
BigDecimal totalExpenseSum = BigDecimal.ZERO;
BigDecimal totalRechargeSum = BigDecimal.ZERO;
Long lineNumber = 1L;
for (WalletManageVo v : list) {
v.setLineNumber(lineNumber);
lineNumber++;
if (ObjectUtil.isNotEmpty(v.getBalance())) {
balanceSum = balanceSum.add(BigDecimal.valueOf(v.getBalance()));
v.setBalanceStr(BigDecimal.valueOf(v.getBalance()).divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
}
if (ObjectUtil.isNotEmpty(v.getTotalExpense())) {
totalExpenseSum = totalExpenseSum.add(BigDecimal.valueOf(v.getTotalExpense()));
v.setTotalExpenseStr(BigDecimal.valueOf(v.getTotalExpense()).divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
}
if (ObjectUtil.isNotEmpty(v.getTotalRecharge())) {
totalRechargeSum = totalRechargeSum.add(BigDecimal.valueOf(v.getTotalRecharge()));
v.setTotalRechargeStr(BigDecimal.valueOf(v.getTotalRecharge()).divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
}
}
map.put("balanceSum", balanceSum.divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
map.put("totalExpenseSum", totalExpenseSum.divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
map.put("totalRechargeSum", totalRechargeSum.divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
}
excelWriter.fill(map, writeSheet);
excelWriter.fill(list, fillConfig, writeSheet);
} catch (IOException e) {
e.printStackTrace();
log.error("|{}|导入错误,dto:|{}|,fileName:|{}|,error:|{}|", TAG, JSON.toJSONString(dto), fileName, e.getMessage());
}
}
@Override
public void exportQb(HttpServletResponse response, Page page, WalletManageBalanceDto dto) {
String fileName = "file/个人钱包记录明细.xlsx";
List<WalletManageVo> list = scopeQbList(dto, DataScope.of());
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(ResourceUtil.getStream(fileName)).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet().build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
Map<String, Object> map = new HashMap<String, Object>();
map.put("walletRecordMonth", dto.getWalletRecordMonth());
if (ObjectUtil.isNotEmpty(list)) {
Long lineNumber = 1L;
BigDecimal balanceSum = BigDecimal.ZERO;
for (WalletManageVo v : list) {
v.setLineNumber(lineNumber);
lineNumber++;
if (ObjectUtil.isNotEmpty(v.getBalance())) {
balanceSum = balanceSum.add(BigDecimal.valueOf(v.getBalance()));
v.setBalanceStr(BigDecimal.valueOf(v.getBalance()).divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
}
}
map.put("balanceSum", balanceSum.divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).toString());
}
excelWriter.fill(map, writeSheet);
excelWriter.fill(list, fillConfig, writeSheet);
} catch (IOException e) {
e.printStackTrace();
log.error("|{}|导入错误,dto:|{}|,fileName:|{}|,error:|{}|", TAG, JSON.toJSONString(dto), fileName, e.getMessage());
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void userChange(Long userId, Boolean isDel) {