准备当日报表数据

This commit is contained in:
2026-04-25 17:13:20 +08:00
parent 46dec3fadb
commit 75f3520e22
3 changed files with 206 additions and 2 deletions

View File

@@ -301,6 +301,48 @@ public class LbDailyUserTradeController {
}
}
@PostMapping("/calculate-report/by-date-and-tenant")
@Operation(summary = "按日期和租户计算报表", description = "根据报表日期和租户ID计算当天交易报表并写入 lb_daily_user_trade_report")
public ResponseEntity<Map<String, Object>> calculateReportByDateAndTenant(
@Parameter(description = "报表日期格式yyyy-MM-dd", required = true)
@RequestParam String reportDate,
@Parameter(description = "租户ID", required = true)
@RequestParam String tenantId) {
Map<String, Object> result = new HashMap<>();
try {
if (tenantId == null || tenantId.trim().isEmpty()) {
result.put("success", false);
result.put("message", "tenantId不能为空");
return ResponseEntity.badRequest().body(result);
}
if (reportDate == null || reportDate.trim().isEmpty()) {
result.put("success", false);
result.put("message", "reportDate不能为空");
return ResponseEntity.badRequest().body(result);
}
LocalDate parsedReportDate;
try {
parsedReportDate = LocalDate.parse(reportDate.trim());
} catch (Exception e) {
result.put("success", false);
result.put("message", "报表日期格式错误,请使用 yyyy-MM-dd");
return ResponseEntity.badRequest().body(result);
}
Map<String, Object> serviceResult = lbDailyUserTradeService.calculateDailyTradeReport(parsedReportDate, tenantId);
Boolean success = (Boolean) serviceResult.get("success");
if (Boolean.TRUE.equals(success)) {
return ResponseEntity.ok(serviceResult);
}
return ResponseEntity.badRequest().body(serviceResult);
} catch (Exception e) {
result.put("success", false);
result.put("message", "计算异常:" + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
@PostMapping("/import")
@Operation(summary = "导入交易记录", description = "按Excel模板导入当天用户交易记录")
public ResponseEntity<Map<String, Object>> importExcel(

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.rj.entity.LbDailyUserTrade;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.util.Map;
/**
@@ -14,4 +15,6 @@ import java.util.Map;
public interface ILbDailyUserTradeService extends IService<LbDailyUserTrade> {
Map<String, Object> importFromExcel(MultipartFile file, String defaultReportDate, String tenantId);
Map<String, Object> calculateDailyTradeReport(LocalDate reportDate, String tenantId);
}

View File

@@ -1,10 +1,13 @@
package com.rj.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.entity.LbDailyUserTrade;
import com.rj.entity.LbDailyUserTradeReport;
import com.rj.mapper.LbDailyUserTradeMapper;
import com.rj.service.ILbDailyUserTradeService;
import com.rj.service.ILbDailyUserTradeReportService;
import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
@@ -16,6 +19,7 @@ import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -46,6 +50,96 @@ import java.util.regex.Pattern;
@Service
public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMapper, LbDailyUserTrade> implements ILbDailyUserTradeService {
private static final Logger log = LoggerFactory.getLogger(LbDailyUserTradeServiceImpl.class);
private static final BigDecimal SERVICE_RATE = new BigDecimal("0.01");
@Autowired
private ILbDailyUserTradeReportService lbDailyUserTradeReportService;
@Override
public Map<String, Object> calculateDailyTradeReport(LocalDate reportDate, String tenantId) {
Map<String, Object> result = new HashMap<>();
if (reportDate == null) {
result.put("success", false);
result.put("message", "reportDate不能为空");
return result;
}
if (StringUtils.isBlank(tenantId)) {
result.put("success", false);
result.put("message", "tenantId不能为空");
return result;
}
String normalizedTenantId = tenantId.trim();
LambdaQueryWrapper<LbDailyUserTrade> currentDayWrapper = new LambdaQueryWrapper<>();
currentDayWrapper.eq(LbDailyUserTrade::getTenantId, normalizedTenantId)
.eq(LbDailyUserTrade::getReportDate, reportDate)
.and(wrapper -> wrapper
.ne(LbDailyUserTrade::getDailySellAmt, BigDecimal.ZERO)
.or()
.ne(LbDailyUserTrade::getDailyBuyAmt, BigDecimal.ZERO)
.or()
.ne(LbDailyUserTrade::getDiffAmt, BigDecimal.ZERO));
List<LbDailyUserTrade> currentDayTrades = this.list(currentDayWrapper);
if (currentDayTrades.isEmpty()) {
result.put("success", true);
result.put("message", "未匹配到可计算数据");
result.put("insertCount", 0);
return result;
}
LocalDate yesterday = reportDate.minusDays(1);
LocalDateTime now = LocalDateTime.now();
List<LbDailyUserTradeReport> reportList = new ArrayList<>();
for (LbDailyUserTrade trade : currentDayTrades) {
BigDecimal dailySellAmt = trade.getDailySellAmt() == null ? BigDecimal.ZERO : trade.getDailySellAmt();
BigDecimal dailyBuyAmt = trade.getDailyBuyAmt() == null ? BigDecimal.ZERO : trade.getDailyBuyAmt();
BigDecimal diffAmt = trade.getDiffAmt() == null ? BigDecimal.ZERO : trade.getDiffAmt();
LambdaQueryWrapper<LbDailyUserTrade> yesterdayWrapper = new LambdaQueryWrapper<>();
yesterdayWrapper.eq(LbDailyUserTrade::getTenantId, normalizedTenantId)
.eq(LbDailyUserTrade::getReportDate, yesterday)
.eq(LbDailyUserTrade::getUserId, trade.getUserId());
if (StringUtils.isNotBlank(trade.getNickname())) {
yesterdayWrapper.eq(LbDailyUserTrade::getNickname, trade.getNickname().trim());
}
yesterdayWrapper
.orderByDesc(LbDailyUserTrade::getUpdatedAt)
.last("limit 1");
LbDailyUserTrade lastDateRecord = this.getOne(yesterdayWrapper, false);
BigDecimal yestodaySellAmt = lastDateRecord == null || lastDateRecord.getDailyBuyAmt() == null
? BigDecimal.ZERO
: lastDateRecord.getDailyBuyAmt();
LbDailyUserTradeReport report = new LbDailyUserTradeReport();
report.setId(UUID.randomUUID().toString());
report.setTenantId(normalizedTenantId);
report.setUserId(trade.getUserId());
report.setNickname(trade.getNickname());
report.setYestodaySellAmt(yestodaySellAmt);
report.setDailySellAmt(dailySellAmt);
report.setDailyBuyAmt(dailyBuyAmt);
report.setServiceAmt(dailyBuyAmt.multiply(SERVICE_RATE));
report.setDiffAmt(diffAmt);
report.setReportDate(reportDate.atStartOfDay());
report.setCreatedAt(now);
report.setUpdatedAt(now);
reportList.add(report);
}
boolean saved = lbDailyUserTradeReportService.saveBatch(reportList);
if (!saved) {
result.put("success", false);
result.put("message", "报表插入失败");
return result;
}
result.put("success", true);
result.put("message", "计算并写入报表成功");
result.put("insertCount", reportList.size());
return result;
}
@Override
public Map<String, Object> importFromExcel(MultipartFile file, String defaultReportDate, String tenantId) {
@@ -204,16 +298,75 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
map.putIfAbsent(field, cell.getColumnIndex());
}
}
completeAmountColumnByOrder(map, headerRow, formatter);
return map;
}
private void completeAmountColumnByOrder(Map<String, Integer> map, Row headerRow, DataFormatter formatter) {
if (map.containsKey("dailySellAmt") && map.containsKey("dailyBuyAmt")) {
return;
}
Integer nicknameIndex = map.get("nickname");
Integer userIdIndex = map.get("userId");
Integer diffIndex = map.get("diffAmt");
int startIndex = -1;
if (nicknameIndex != null) {
startIndex = nicknameIndex;
} else if (userIdIndex != null) {
startIndex = userIdIndex;
}
if (startIndex < 0) {
return;
}
int candidateSellIndex = startIndex + 1;
int candidateBuyIndex = startIndex + 2;
int lastCellNum = headerRow.getLastCellNum();
if (lastCellNum < 0) {
return;
}
if (diffIndex != null) {
if (candidateSellIndex >= diffIndex || candidateBuyIndex >= diffIndex) {
candidateSellIndex = -1;
candidateBuyIndex = -1;
for (int i = startIndex + 1; i < diffIndex; i++) {
String header = normalizeHeader(formatter.formatCellValue(headerRow.getCell(i)));
if (header.isEmpty()) {
continue;
}
if (candidateSellIndex < 0) {
candidateSellIndex = i;
} else {
candidateBuyIndex = i;
break;
}
}
}
}
if (!map.containsKey("dailySellAmt")
&& candidateSellIndex >= 0
&& candidateSellIndex < lastCellNum) {
map.put("dailySellAmt", candidateSellIndex);
}
if (!map.containsKey("dailyBuyAmt")
&& candidateBuyIndex >= 0
&& candidateBuyIndex < lastCellNum) {
map.put("dailyBuyAmt", candidateBuyIndex);
}
}
private String resolveFieldByHeader(String header) {
Map<String, Set<String>> aliasMap = new HashMap<>();
aliasMap.put("tenantId", Set.of("tenantid", "tenant_id", "租户id", "租户"));
aliasMap.put("userId", Set.of("userid", "user_id", "用户id", "用户"));
aliasMap.put("nickname", Set.of("nickname", "昵称", "用户名", "客户昵称"));
aliasMap.put("dailySellAmt", Set.of("dailysellamt", "daily_sell_amt", "单日卖出金额", "卖出金额", "卖出"));
aliasMap.put("dailyBuyAmt", Set.of("dailybuyamt", "daily_buy_amt", "当日买入金额", "买入金额", "买入"));
aliasMap.put("dailySellAmt", Set.of("dailysellamt", "daily_sell_amt", "单日卖出金额", "卖出金额", "卖出", "卖总"));
aliasMap.put("dailyBuyAmt", Set.of("dailybuyamt", "daily_buy_amt", "当日买入金额", "买入金额", "买入", "买总"));
aliasMap.put("diffAmt", Set.of("diffamt", "diff_amt", "差额", "净额"));
aliasMap.put("promoterId", Set.of("promoterid", "promoter_id", "推广人id"));
aliasMap.put("promoterName", Set.of("promotername", "promoter_name", "推广人", "邀请人"));
@@ -225,6 +378,12 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
return entry.getKey();
}
}
if (header.contains("") && header.contains("")) {
return "dailySellAmt";
}
if (header.contains("") && header.contains("")) {
return "dailyBuyAmt";
}
return null;
}