调整代码结构

This commit is contained in:
2026-04-25 14:53:54 +08:00
parent 217422f422
commit 4ce1cf326e
10 changed files with 391 additions and 74 deletions

View File

@@ -1,17 +0,0 @@
package com.rj.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.entity.DailyUserTrade;
import com.rj.mapper.DailyUserTradeMapper;
import com.rj.service.IDailyUserTradeService;
import org.springframework.stereotype.Service;
/**
* <p>
* 当天用户交易表 服务实现类
* </p>
*/
@Service
public class DailyUserTradeServiceImpl extends ServiceImpl<DailyUserTradeMapper, DailyUserTrade> implements IDailyUserTradeService {
}

View File

@@ -0,0 +1,280 @@
package com.rj.service.impl;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.entity.LbDailyUserTrade;
import com.rj.mapper.LbDailyUserTradeMapper;
import com.rj.service.ILbDailyUserTradeService;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
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;
import java.util.Set;
import java.util.UUID;
/**
* <p>
* 当天用户交易表 服务实现类
* </p>
*/
@Service
public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMapper, LbDailyUserTrade> implements ILbDailyUserTradeService {
@Override
public Map<String, Object> importFromExcel(MultipartFile file, String defaultReportDate) {
Map<String, Object> result = new HashMap<>();
if (file == null || file.isEmpty()) {
result.put("success", false);
result.put("message", "上传文件不能为空");
return result;
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".xlsx")) {
result.put("success", false);
result.put("message", "仅支持 .xlsx 文件");
return result;
}
LocalDate fallbackReportDate = null;
if (StringUtils.isNotBlank(defaultReportDate)) {
try {
fallbackReportDate = LocalDate.parse(defaultReportDate.trim());
} catch (Exception e) {
result.put("success", false);
result.put("message", "defaultReportDate 格式错误,请使用 yyyy-MM-dd");
return result;
}
}
List<LbDailyUserTrade> importList = new ArrayList<>();
List<String> skippedRows = new ArrayList<>();
DataFormatter dataFormatter = new DataFormatter();
try (Workbook workbook = new XSSFWorkbook(file.getInputStream())) {
Sheet sheet = workbook.getSheetAt(0);
if (sheet == null) {
result.put("success", false);
result.put("message", "Excel内容为空");
return result;
}
int headerRowNum = findHeaderRow(sheet, dataFormatter);
if (headerRowNum < 0) {
result.put("success", false);
result.put("message", "未识别到表头请确认模板列包含租户ID、用户ID、单日卖出金额、当日买入金额等字段");
return result;
}
Map<String, Integer> headerIndexMap = buildHeaderIndexMap(sheet.getRow(headerRowNum), dataFormatter);
for (int i = headerRowNum + 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null || isEmptyRow(row, dataFormatter)) {
continue;
}
try {
LbDailyUserTrade trade = parseTradeRow(row, headerIndexMap, dataFormatter, fallbackReportDate);
if (trade == null) {
skippedRows.add(String.valueOf(i + 1));
continue;
}
importList.add(trade);
} catch (Exception ex) {
skippedRows.add((i + 1) + "(" + ex.getMessage() + ")");
}
}
} catch (IOException e) {
result.put("success", false);
result.put("message", "读取Excel失败" + e.getMessage());
return result;
}
if (importList.isEmpty()) {
result.put("success", false);
result.put("message", "没有可导入的数据,请检查模板与内容");
result.put("skippedRows", skippedRows);
return result;
}
boolean saved = this.saveBatch(importList);
if (!saved) {
result.put("success", false);
result.put("message", "导入失败,数据库保存异常");
return result;
}
result.put("success", true);
result.put("message", "导入成功");
result.put("importCount", importList.size());
result.put("skipCount", skippedRows.size());
result.put("skippedRows", skippedRows);
return result;
}
private int findHeaderRow(Sheet sheet, DataFormatter formatter) {
int maxRow = Math.min(sheet.getLastRowNum(), 10);
for (int i = 0; i <= maxRow; i++) {
Row row = sheet.getRow(i);
if (row == null) {
continue;
}
Map<String, Integer> headerMap = buildHeaderIndexMap(row, formatter);
if (headerMap.containsKey("tenantId") && headerMap.containsKey("userId")) {
return i;
}
}
return -1;
}
private Map<String, Integer> buildHeaderIndexMap(Row headerRow, DataFormatter formatter) {
Map<String, Integer> map = new HashMap<>();
if (headerRow == null) {
return map;
}
for (Cell cell : headerRow) {
String text = normalizeHeader(formatter.formatCellValue(cell));
if (text.isEmpty()) {
continue;
}
String field = resolveFieldByHeader(text);
if (field != null) {
map.putIfAbsent(field, cell.getColumnIndex());
}
}
return map;
}
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("diffAmt", Set.of("diffamt", "diff_amt", "差额", "净额"));
aliasMap.put("promoterId", Set.of("promoterid", "promoter_id", "推广人id"));
aliasMap.put("promoterName", Set.of("promotername", "promoter_name", "推广人", "邀请人"));
aliasMap.put("descContent", Set.of("desccontent", "desc_content", "描述", "备注", "说明"));
aliasMap.put("reportDate", Set.of("reportdate", "report_date", "报表日期", "统计日期", "日期"));
for (Map.Entry<String, Set<String>> entry : aliasMap.entrySet()) {
if (entry.getValue().contains(header)) {
return entry.getKey();
}
}
return null;
}
private LbDailyUserTrade parseTradeRow(Row row, Map<String, Integer> headerMap, DataFormatter formatter, LocalDate fallbackReportDate) {
String tenantId = readString(row, headerMap.get("tenantId"), formatter);
String userId = readString(row, headerMap.get("userId"), formatter);
if (tenantId.isEmpty() || userId.isEmpty()) {
return null;
}
LbDailyUserTrade trade = new LbDailyUserTrade();
trade.setId(UUID.randomUUID().toString());
trade.setTenantId(tenantId);
trade.setUserId(userId);
trade.setNickname(readString(row, headerMap.get("nickname"), formatter));
trade.setDailySellAmt(readDecimal(row, headerMap.get("dailySellAmt"), formatter));
trade.setDailyBuyAmt(readDecimal(row, headerMap.get("dailyBuyAmt"), formatter));
trade.setPromoterId(readString(row, headerMap.get("promoterId"), formatter));
trade.setPromoterName(readString(row, headerMap.get("promoterName"), formatter));
trade.setDescContent(readString(row, headerMap.get("descContent"), formatter));
BigDecimal sell = trade.getDailySellAmt() == null ? BigDecimal.ZERO : trade.getDailySellAmt();
BigDecimal buy = trade.getDailyBuyAmt() == null ? BigDecimal.ZERO : trade.getDailyBuyAmt();
BigDecimal diff = readDecimal(row, headerMap.get("diffAmt"), formatter);
trade.setDailySellAmt(sell);
trade.setDailyBuyAmt(buy);
trade.setDiffAmt(diff == null ? sell.subtract(buy) : diff);
LocalDate reportDate = readDate(row, headerMap.get("reportDate"), formatter);
trade.setReportDate(reportDate != null ? reportDate : (fallbackReportDate != null ? fallbackReportDate : LocalDate.now()));
trade.setCreatedAt(LocalDateTime.now());
trade.setUpdatedAt(LocalDateTime.now());
return trade;
}
private boolean isEmptyRow(Row row, DataFormatter formatter) {
for (Cell cell : row) {
if (!formatter.formatCellValue(cell).trim().isEmpty()) {
return false;
}
}
return true;
}
private String readString(Row row, Integer index, DataFormatter formatter) {
if (index == null) {
return "";
}
Cell cell = row.getCell(index);
if (cell == null) {
return "";
}
return formatter.formatCellValue(cell).trim();
}
private BigDecimal readDecimal(Row row, Integer index, DataFormatter formatter) {
String value = readString(row, index, formatter);
if (value.isEmpty()) {
return BigDecimal.ZERO;
}
String normalized = value.replace(",", "").replace("", "");
try {
return new BigDecimal(normalized);
} catch (Exception e) {
throw new IllegalArgumentException("金额格式错误: " + value);
}
}
private LocalDate readDate(Row row, Integer index, DataFormatter formatter) {
if (index == null) {
return null;
}
Cell cell = row.getCell(index);
if (cell == null) {
return null;
}
if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) {
return cell.getLocalDateTimeCellValue().toLocalDate();
}
String text = formatter.formatCellValue(cell).trim();
if (text.isEmpty()) {
return null;
}
try {
return LocalDate.parse(text);
} catch (Exception ignore) {
}
try {
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy/MM/dd"));
} catch (Exception ignore) {
}
try {
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-M-d"));
} catch (Exception ignore) {
}
throw new IllegalArgumentException("日期格式错误: " + text);
}
private String normalizeHeader(String header) {
return header == null ? "" : header.toLowerCase().replace(" ", "").replace(" ", "").trim();
}
}