报表导出

This commit is contained in:
2026-05-25 22:33:27 +08:00
parent 62722a9ce7
commit c0fed06eaa
9 changed files with 825 additions and 9 deletions

View File

@@ -14,11 +14,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.rj.dto.hxr.HxrUserRow;
import com.rj.entity.LbDailyUserTrade;
import com.rj.entity.LbDailyUserTradeReport;
import com.rj.entity.LbOrderRow;
import com.rj.entity.LbPurchaseApply;
import com.rj.entity.LbUser;
import com.rj.util.IsoWorkdayUtils;
import com.rj.mapper.LbDailyUserTradeMapper;
import com.rj.mapper.LbDailyUserTradeReportMapper;
import com.rj.mapper.LbOrderRowMapper;
import com.rj.mapper.LbPurchaseApplyMapper;
import com.rj.mapper.LbUserMapper;
import com.rj.service.HxrAdminUserService;
@@ -46,6 +48,7 @@ import java.util.HashSet;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -71,12 +74,22 @@ public class LbPurchaseApplyServiceImpl
@Autowired
private LbUserMapper lbUserMapper;
@Autowired
private LbOrderRowMapper lbOrderRowMapper;
@Autowired
private ObjectMapper objectMapper;
@Value("${langchain4j.open-ai.chat-model.model-name:qwen-plus}")
private String dashScopeChatModel;
private static final String ORDER_DATA_TYPE_DETAIL = "detail_data";
private static final DateTimeFormatter ORDER_DAY_TIME_FMT =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final DateTimeFormatter ORDER_DAY_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter TRY_DATE_MM_DD = DateTimeFormatter.ofPattern("MM.dd");
private static final DateTimeFormatter PRIVILEGE_RANGE_FMT = DateTimeFormatter.ofPattern("MM.dd");
private static final DateTimeFormatter EXPORT_FILENAME_TS = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
@@ -447,6 +460,7 @@ public class LbPurchaseApplyServiceImpl
Page<LbPurchaseApply> page = this.page(new Page<>(current, size), queryWrapper);
fillLinkedLbUsers(page.getRecords());
fillLatestTradeOrders(page.getRecords());
result.put("success", true);
result.put("message", "查询成功");
result.put("data", page.getRecords());
@@ -507,6 +521,133 @@ public class LbPurchaseApplyServiceImpl
}
}
/**
* 按租户 + 申请人手机号关联 {@link LbOrderRow}:{@code apply_phone} 匹配 {@code buyer_phone},
* 取 pay_time 最近的一条已成交明细订单。
*/
private void fillLatestTradeOrders(List<LbPurchaseApply> records) {
if (records == null || records.isEmpty()) {
return;
}
Set<String> buyerPhones = new HashSet<>();
Set<String> tenantIds = new HashSet<>();
for (LbPurchaseApply record : records) {
String applyPhone = trimToNull(record.getApplyPhone());
if (applyPhone != null) {
buyerPhones.add(applyPhone);
}
String tenantId = trimToNull(record.getTenantId());
if (tenantId != null) {
tenantIds.add(tenantId);
}
}
if (buyerPhones.isEmpty()) {
return;
}
LambdaQueryWrapper<LbOrderRow> orderQuery = new LambdaQueryWrapper<>();
orderQuery.eq(LbOrderRow::getDataType, ORDER_DATA_TYPE_DETAIL)
.in(LbOrderRow::getBuyerPhone, buyerPhones)
.isNotNull(LbOrderRow::getPayTime);
if (tenantIds.size() == 1) {
orderQuery.eq(LbOrderRow::getTenantId, tenantIds.iterator().next());
} else if (tenantIds.size() > 1) {
orderQuery.in(LbOrderRow::getTenantId, tenantIds);
}
List<LbOrderRow> orderRows = lbOrderRowMapper.selectList(orderQuery);
if (orderRows == null || orderRows.isEmpty()) {
return;
}
Map<String, LbOrderRow> latestByTenantPhone = new HashMap<>();
for (LbOrderRow row : orderRows) {
if (!isPaidOrderRow(row)) {
continue;
}
String buyerPhone = trimToNull(row.getBuyerPhone());
if (buyerPhone == null) {
continue;
}
String key = buildTenantMobileKey(row.getTenantId(), buyerPhone);
LbOrderRow prev = latestByTenantPhone.get(key);
if (prev == null || isOrderPayTimeNewer(row, prev)) {
latestByTenantPhone.put(key, row);
}
}
for (LbPurchaseApply record : records) {
String applyPhone = trimToNull(record.getApplyPhone());
if (applyPhone == null) {
continue;
}
LbOrderRow latest = latestByTenantPhone.get(buildTenantMobileKey(record.getTenantId(), applyPhone));
if (latest != null) {
record.setLatestTradeOrder(latest);
}else {
record.setLatestTradeOrder(new LbOrderRow());
}
}
}
private static boolean isPaidOrderRow(LbOrderRow row) {
String payTime = row.getPayTime();
return payTime != null && !payTime.trim().isEmpty();
}
private static boolean isOrderPayTimeNewer(LbOrderRow order, LbOrderRow prev) {
LocalDateTime payTime = parseOrderTime(payTimeOrBuyTime(order));
LocalDateTime prevPayTime = parseOrderTime(payTimeOrBuyTime(prev));
if (payTime == null) {
return false;
}
if (prevPayTime == null) {
return true;
}
int cmp = payTime.compareTo(prevPayTime);
if (cmp != 0) {
return cmp > 0;
}
Long id = order.getId();
Long prevId = prev.getId();
if (id == null) {
return false;
}
if (prevId == null) {
return true;
}
return id > prevId;
}
private static String payTimeOrBuyTime(LbOrderRow row) {
if (row.getPayTime() != null && !row.getPayTime().trim().isEmpty()) {
return row.getPayTime().trim();
}
return row.getBuyTime() == null ? null : row.getBuyTime().trim();
}
private static LocalDateTime parseOrderTime(String timeText) {
if (timeText == null || timeText.isEmpty()) {
return null;
}
try {
return LocalDateTime.parse(timeText, ORDER_DAY_TIME_FMT);
} catch (DateTimeParseException ignored) {
// continue
}
try {
return LocalDate.parse(timeText.substring(0, Math.min(10, timeText.length())), ORDER_DAY_FMT)
.atStartOfDay();
} catch (DateTimeParseException ignored) {
// continue
}
try {
return LocalDateTime.parse(timeText, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
} catch (DateTimeParseException e) {
return null;
}
}
/**
* 分页关联用户时仅暴露业务所需字段,其余置空或 0,避免泄露手机号、密码等隐私。
*/