调度补齐卖家姓名和电话

This commit is contained in:
2026-05-18 13:31:29 +08:00
parent fb1a86f0e0
commit 457de72b27
12 changed files with 383 additions and 45 deletions

View File

@@ -17,11 +17,28 @@ public class HxrAdminProperties {
private boolean enabled = true; private boolean enabled = true;
/** /**
* 完整请求 URL含查询串与浏览器地址栏一致即可 * 订单列表基础 URL含分页等通用查询串各业务在代码中覆盖查询参数或使用独立 URL 配置
*/ */
private String orderSelectUrl = private String orderSelectUrl =
"https://hxrdhoutai.hxrdsm.cn/app/admin/order/select?page=1&limit=90"; "https://hxrdhoutai.hxrdsm.cn/app/admin/order/select?page=1&limit=90";
/**
* 未支付订单拉取 URL含 {@code status=0} 等业务筛选),供 {@link LBAdminPullScheduler#pullOrdersForUnPay} 使用。
*/
private String orderSelectUnPayUrl =
"https://hxrdhoutai.hxrdsm.cn/app/admin/order/select?page=1&limit=90&status=0";
/**
* 已支付订单拉取 URL含 {@code status=1}),供 {@link LBAdminPullScheduler#pullOrdersForUnPay} 使用。
*/
private String orderSelectPaidUrl =
"https://hxrdhoutai.hxrdsm.cn/app/admin/order/select?page=1&limit=90&status=1";
/**
* 定时将 hxrd 订单同步到 {@code lb_order_row} 时使用的租户 id未配置时跳过订单状态同步。
*/
private String syncTenantId = "TENANT_ID_CST_2026";
/** /**
* 请求头 Cookie 完整取值,例如 {@code PHPSID=xxxx}。非空时优先于 {@link #phpsid}。 * 请求头 Cookie 完整取值,例如 {@code PHPSID=xxxx}。非空时优先于 {@link #phpsid}。
*/ */

View File

@@ -7,6 +7,8 @@ public record HxrOrderRow(
long id, long id,
Long oldId, Long oldId,
long sellerId, long sellerId,
String sellerName,
String sellerPhone,
long buyerId, long buyerId,
String orderSn, String orderSn,
String totalMoney, String totalMoney,

View File

@@ -40,6 +40,14 @@ public class LbOrderRow implements Serializable {
@Schema(description = "卖家 id") @Schema(description = "卖家 id")
private Long sellerId; private Long sellerId;
@TableField("seller_name")
@Schema(description = "卖家姓名")
private String sellerName;
@TableField("seller_phone")
@Schema(description = "卖家电话")
private String sellerPhone;
@TableField("buyer_id") @TableField("buyer_id")
@Schema(description = "买家 id") @Schema(description = "买家 id")
private Long buyerId; private Long buyerId;

View File

@@ -1,9 +1,19 @@
package com.rj.mapper; package com.rj.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.rj.entity.LbOrderRow; import com.rj.entity.LbOrderRow;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper @Mapper
public interface LbOrderRowMapper extends BaseMapper<LbOrderRow> { public interface LbOrderRowMapper extends BaseMapper<LbOrderRow> {
/**
* 按订单 id主键插入或更新跳过租户行拦截避免 listByIds 因 tenant_id 过滤漏判导致重复插入。
*/
@InterceptorIgnore(tenantLine = "true")
int upsertBatch(@Param("list") List<LbOrderRow> list);
} }

View File

@@ -3,16 +3,21 @@ package com.rj.scheduler;
import com.rj.config.AppConfig; import com.rj.config.AppConfig;
import com.rj.config.HxrAdminProperties; import com.rj.config.HxrAdminProperties;
import com.rj.service.HxrAdminOrderSelectService; import com.rj.service.HxrAdminOrderSelectService;
import com.rj.service.ILbOrderRowService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Map;
import java.time.Clock; import java.time.Clock;
import java.time.DayOfWeek; import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/** /**
* hxrd 后台订单列表定时拉取:每 50 分钟触发一次,仅工作日(周一至周五)且在每天 18:1023:59:59应用时区内真正执行。 * hxrd 后台订单列表定时拉取:每 50 分钟触发一次,仅工作日(周一至周五)且在每天 18:1023:59:59应用时区内真正执行。
@@ -22,11 +27,15 @@ import java.time.ZonedDateTime;
@RequiredArgsConstructor @RequiredArgsConstructor
public class LBAdminPullScheduler { public class LBAdminPullScheduler {
private static final long FIFTY_MINUTES_MS = 50L * 60L * 1000L; private static final long FIFTY_MINUTES_MS = 30L * 60L * 1000L;
private static final long UnPay_MINUTES_MS = 20L * 60L * 1000L;
private static final DateTimeFormatter BUY_TIME_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final AppConfig appConfig; private final AppConfig appConfig;
private final HxrAdminProperties hxrAdminProperties; private final HxrAdminProperties hxrAdminProperties;
private final HxrAdminOrderSelectService hxrAdminOrderSelectService; private final HxrAdminOrderSelectService hxrAdminOrderSelectService;
private final ILbOrderRowService lbOrderRowService;
private final Clock clock; private final Clock clock;
@Scheduled( @Scheduled(
@@ -63,4 +72,80 @@ public class LBAdminPullScheduler {
log.error("未寄卖 admin 订单拉取失败", e); log.error("未寄卖 admin 订单拉取失败", e);
} }
} }
private static final int HXR_ORDER_STATUS_UNPAID = 0;
private static final int HXR_ORDER_STATUS_PAID = 1;
/**
* 未支付/已支付订单同步:工作日每天 11:0015:00应用时区仅在窗口内真正执行。
*/
@Scheduled(
fixedRate = UnPay_MINUTES_MS,
initialDelayString = "${hxr.admin.pull-initial-delay-ms:0}")
public void pullOrdersForUnPay() {
try {
if (!appConfig.getScheduler().isStart()) {
log.debug("全局调度未启用,跳过 未支付 订单拉取");
return;
}
if (!hxrAdminProperties.isEnabled()) {
log.debug("hxr.admin.enabled=false跳过订单拉取");
return;
}
ZoneId zone = ZoneId.of(appConfig.getTimezone());
ZonedDateTime nowZdt = ZonedDateTime.now(clock.withZone(zone));
DayOfWeek dow = nowZdt.getDayOfWeek();
if (dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY) {
log.debug("当前为周末 {},跳过 未支付 订单拉取", dow);
return;
}
LocalTime now = nowZdt.toLocalTime();
LocalTime windowStart = LocalTime.of(11, 0);
LocalTime windowEnd = LocalTime.of(15, 0);
if (now.isBefore(windowStart) || now.isAfter(windowEnd)) {
log.debug("当前时刻 {} 不在窗口 {}{},跳过 未支付 订单拉取", now, windowStart, windowEnd);
return;
}
String tenantId = hxrAdminProperties.getSyncTenantId();
if (tenantId == null || tenantId.isBlank()) {
log.warn("hxr.admin.sync-tenant-id 未配置,跳过订单状态同步");
return;
}
LocalDate today = nowZdt.toLocalDate();
String buyTimeStart = today.atStartOfDay().format(BUY_TIME_FMT);
String buyTimeEnd = today.atTime(23, 59, 59).format(BUY_TIME_FMT);
String tid = tenantId.trim();
syncOrdersByHxrStatus(tid, buyTimeStart, buyTimeEnd, HXR_ORDER_STATUS_UNPAID, "未支付");
syncOrdersByHxrStatus(tid, buyTimeStart, buyTimeEnd, HXR_ORDER_STATUS_PAID, "已支付");
} catch (Exception e) {
log.error("订单状态同步失败", e);
}
}
private void syncOrdersByHxrStatus(
String tenantId, String buyTimeStart, String buyTimeEnd, int hxrOrderStatus, String label) {
log.info(
"开始执行 {} 订单同步 status={} tenantId={} buyTime={}{}",
label,
hxrOrderStatus,
tenantId,
buyTimeStart,
buyTimeEnd);
Map<String, Object> syncResult =
lbOrderRowService.syncFromHxrAdmin(buyTimeStart, buyTimeEnd, tenantId, null, hxrOrderStatus);
if (Boolean.TRUE.equals(syncResult.get("success"))) {
log.info(
"{}订单同步完成 synced={} remoteCount={}",
label,
syncResult.get("synced"),
syncResult.get("remoteCount"));
} else {
log.warn("{}订单同步失败: {}", label, syncResult.get("message"));
}
}
} }

View File

@@ -40,6 +40,13 @@ public class HxrAdminOrderSelectService {
return fetchOrderSelectInternal(properties.getOrderSelectUrl()); return fetchOrderSelectInternal(properties.getOrderSelectUrl());
} }
/**
* 拉取未支付订单,使用 {@link HxrAdminProperties#getOrderSelectUnPayUrl()}。
*/
public Optional<HxrOrderSelectResponse> fetchUnpaidOrderSelect() throws Exception {
return fetchOrderSelectInternal(properties.getOrderSelectUnPayUrl());
}
/** /**
* 按购买时间区间、转卖状态等条件拉取订单列表(在配置的 {@code orderSelectUrl} 上覆盖查询参数)。 * 按购买时间区间、转卖状态等条件拉取订单列表(在配置的 {@code orderSelectUrl} 上覆盖查询参数)。
* *
@@ -62,6 +69,24 @@ public class HxrAdminOrderSelectService {
return fetchOrderSelectInternal(buildOrderSelectUrl(buyTimeStart, buyTimeEnd, isResell, page)); return fetchOrderSelectInternal(buildOrderSelectUrl(buyTimeStart, buyTimeEnd, isResell, page));
} }
/**
* 按购买时间区间及页码拉取未支付订单({@code status=0},基于 {@link HxrAdminProperties#getOrderSelectUnPayUrl()})。
*/
public Optional<HxrOrderSelectResponse> fetchUnpaidOrderSelect(
String buyTimeStart, String buyTimeEnd, int page) throws Exception {
return fetchOrderSelectInternal(
buildStatusOrderSelectUrl(properties.getOrderSelectUnPayUrl(), buyTimeStart, buyTimeEnd, page));
}
/**
* 按购买时间区间及页码拉取已支付订单({@code status=1},基于 {@link HxrAdminProperties#getOrderSelectPaidUrl()})。
*/
public Optional<HxrOrderSelectResponse> fetchPaidOrderSelect(
String buyTimeStart, String buyTimeEnd, int page) throws Exception {
return fetchOrderSelectInternal(
buildStatusOrderSelectUrl(properties.getOrderSelectPaidUrl(), buyTimeStart, buyTimeEnd, page));
}
private Optional<HxrOrderSelectResponse> fetchOrderSelectInternal(String requestUri) throws Exception { private Optional<HxrOrderSelectResponse> fetchOrderSelectInternal(String requestUri) throws Exception {
String cookieHeader = properties.resolveCookieHeader(); String cookieHeader = properties.resolveCookieHeader();
if (cookieHeader == null || cookieHeader.isBlank()) { if (cookieHeader == null || cookieHeader.isBlank()) {
@@ -115,16 +140,35 @@ public class HxrAdminOrderSelectService {
return b.build().encode().toUriString(); return b.build().encode().toUriString();
} }
private String buildStatusOrderSelectUrl(String baseUrl, String buyTimeStart, String buyTimeEnd, int page) {
UriComponentsBuilder b = UriComponentsBuilder.fromUriString(baseUrl);
b.replaceQueryParam("buy_time[0]", buyTimeStart == null ? "" : buyTimeStart);
b.replaceQueryParam("buy_time[1]", buyTimeEnd == null ? "" : buyTimeEnd);
b.replaceQueryParam("page", Math.max(1, page));
return b.build().encode().toUriString();
}
/** /**
* 拉取并逐条打日志(一行一条 JSON * 拉取并逐条打日志(一行一条 JSON
*/ */
public void fetchAndLogEachOrder() throws Exception { public void fetchAndLogEachOrder() throws Exception {
Optional<HxrOrderSelectResponse> opt = fetchOrderSelect(); fetchAndLogEachOrder(fetchOrderSelect(), "未寄卖");
}
/**
* 拉取未支付订单({@code status=0})并逐条打日志。
*/
public void fetchAndLogUnpaidOrders() throws Exception {
fetchAndLogEachOrder(fetchUnpaidOrderSelect(), "未支付");
}
private void fetchAndLogEachOrder(
Optional<HxrOrderSelectResponse> opt, String label) throws Exception {
if (opt.isEmpty()) { if (opt.isEmpty()) {
return; return;
} }
HxrOrderSelectResponse body = opt.get(); HxrOrderSelectResponse body = opt.get();
log.info("未寄卖 order/select ok count={} allMoney={}", body.count(), body.allMoney()); log.info("{} order/select ok count={} allMoney={}", label, body.count(), body.allMoney());
for (HxrOrderRow row : body.data()) { for (HxrOrderRow row : body.data()) {
log.info("hxr order row {}", JSON.writeValueAsString(row)); log.info("hxr order row {}", JSON.writeValueAsString(row));
} }

View File

@@ -34,6 +34,17 @@ public interface ILbOrderRowService extends IService<LbOrderRow> {
String tenantId, String tenantId,
Integer isResell); Integer isResell);
/**
* 同 {@link #syncFromHxrAdmin(String, String, String, Integer)}{@code hxrOrderStatus} 非空时按后台
* {@code status} 筛选拉取(如 {@code 0} 未支付、{@code 1} 已支付),为 null 时使用通用订单列表 URL。
*/
Map<String, Object> syncFromHxrAdmin(
String buyTimeStart,
String buyTimeEnd,
String tenantId,
Integer isResell,
Integer hxrOrderStatus);
/** /**
* 按购买时间区间与租户查询明细,按天汇总为 {@code sum_data} 写入 {@code lb_order_row}。 * 按购买时间区间与租户查询明细,按天汇总为 {@code sum_data} 写入 {@code lb_order_row}。
*/ */

View File

@@ -5,10 +5,14 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rj.dto.hxr.HxrOrderRow; import com.rj.dto.hxr.HxrOrderRow;
import com.rj.dto.hxr.HxrOrderSelectResponse; import com.rj.dto.hxr.HxrOrderSelectResponse;
import com.rj.entity.LbDepartmentUser;
import com.rj.entity.LbOrderRow; import com.rj.entity.LbOrderRow;
import com.rj.mapper.LbOrderRowMapper; import com.rj.mapper.LbOrderRowMapper;
import com.rj.service.HxrAdminOrderSelectService; import com.rj.service.HxrAdminOrderSelectService;
import com.rj.service.ILbDepartmentUserService;
import com.rj.service.ILbOrderRowService; import com.rj.service.ILbOrderRowService;
import com.rj.tenant.TenantContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -20,11 +24,14 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
@Slf4j
@Service @Service
public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrderRow> implements ILbOrderRowService { public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrderRow> implements ILbOrderRowService {
@@ -47,6 +54,9 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
@Autowired @Autowired
private HxrAdminOrderSelectService hxrAdminOrderSelectService; private HxrAdminOrderSelectService hxrAdminOrderSelectService;
@Autowired
private ILbDepartmentUserService lbDepartmentUserService;
@Override @Override
public Map<String, Object> add(LbOrderRow entity) { public Map<String, Object> add(LbOrderRow entity) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
@@ -224,6 +234,13 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Map<String, Object> syncFromHxrAdmin( public Map<String, Object> syncFromHxrAdmin(
String buyTimeStart, String buyTimeEnd, String tenantId, Integer isResell) { String buyTimeStart, String buyTimeEnd, String tenantId, Integer isResell) {
return syncFromHxrAdmin(buyTimeStart, buyTimeEnd, tenantId, isResell, null);
}
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> syncFromHxrAdmin(
String buyTimeStart, String buyTimeEnd, String tenantId, Integer isResell, Integer hxrOrderStatus) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
try { try {
if (tenantId == null || tenantId.trim().isEmpty()) { if (tenantId == null || tenantId.trim().isEmpty()) {
@@ -234,13 +251,15 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
String tid = tenantId.trim(); String tid = tenantId.trim();
String previousTenantId = TenantContextHolder.getTenantId();
TenantContextHolder.setTenantId(tid);
try {
HxrOrderSelectResponse firstBody = null; HxrOrderSelectResponse firstBody = null;
int page = 1; int page = 1;
int totalSynced = 0; int totalSynced = 0;
while (true) { while (true) {
Optional<HxrOrderSelectResponse> opt = Optional<HxrOrderSelectResponse> opt =
hxrAdminOrderSelectService.fetchOrderSelect( fetchHxrOrderPage(buyTimeStart, buyTimeEnd, isResell, hxrOrderStatus, page);
buyTimeStart, buyTimeEnd, isResell, page);
if (opt.isEmpty()) { if (opt.isEmpty()) {
if (page == 1) { if (page == 1) {
result.put("success", false); result.put("success", false);
@@ -273,9 +292,9 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
for (HxrOrderRow row : rows) { for (HxrOrderRow row : rows) {
entities.add(toLbOrderRow(row, tid)); entities.add(toLbOrderRow(row, tid));
} }
fillSellerInfoFromDepartmentUsers(entities, tid);
boolean ok = this.saveOrUpdateBatch(entities); int upserted = upsertBatch(entities);
if (!ok) { if (upserted < 0) {
result.put("success", false); result.put("success", false);
result.put("message", "" + page + " 页保存失败,已成功同步前 " result.put("message", "" + page + " 页保存失败,已成功同步前 "
+ (page - 1) + " 页共 " + totalSynced + ""); + (page - 1) + " 页共 " + totalSynced + "");
@@ -285,7 +304,7 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
result.put("pages", page - 1); result.put("pages", page - 1);
return result; return result;
} }
totalSynced += entities.size(); totalSynced += upserted;
if (rows.size() < HXR_ORDER_PAGE_SIZE ) { if (rows.size() < HXR_ORDER_PAGE_SIZE ) {
break; break;
@@ -309,14 +328,40 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
result.put("allMoney", firstBody.allMoney()); result.put("allMoney", firstBody.allMoney());
result.put("pages", page); result.put("pages", page);
return result; return result;
} finally {
if (previousTenantId != null) {
TenantContextHolder.setTenantId(previousTenantId);
} else {
TenantContextHolder.clear();
}
}
} catch (Exception e) { } catch (Exception e) {
result.put("success", false); result.put("success", false);
result.put("message", "同步异常:" + e.getMessage()); result.put("message", "同步异常:" + e.getMessage());
result.put("synced", 0); result.put("synced", 0);
log.error("syncFromHxrAdmin failed", e);
return result; return result;
} }
} }
private Optional<HxrOrderSelectResponse> fetchHxrOrderPage(
String buyTimeStart,
String buyTimeEnd,
Integer isResell,
Integer hxrOrderStatus,
int page)
throws Exception {
if (hxrOrderStatus != null) {
if (hxrOrderStatus == 0) {
return hxrAdminOrderSelectService.fetchUnpaidOrderSelect(buyTimeStart, buyTimeEnd, page);
}
if (hxrOrderStatus == 1) {
return hxrAdminOrderSelectService.fetchPaidOrderSelect(buyTimeStart, buyTimeEnd, page);
}
}
return hxrAdminOrderSelectService.fetchOrderSelect(buyTimeStart, buyTimeEnd, isResell, page);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Map<String, Object> generateDailySumData( public Map<String, Object> generateDailySumData(
@@ -373,10 +418,11 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
sumRows.add(buildDailySumRow(tid, entry.getKey(), entry.getValue(), nowStr)); sumRows.add(buildDailySumRow(tid, entry.getKey(), entry.getValue(), nowStr));
} }
boolean ok = this.saveOrUpdateBatch(sumRows); int upserted = upsertBatch(sumRows);
boolean ok = upserted >= 0;
result.put("success", ok); result.put("success", ok);
result.put("message", ok ? "按日汇总完成" : "保存失败"); result.put("message", ok ? "按日汇总完成" : "保存失败");
result.put("generated", ok ? sumRows.size() : 0); result.put("generated", ok ? upserted : 0);
result.put("sourceCount", details.size()); result.put("sourceCount", details.size());
result.put("skippedNoBuyTime", skippedNoBuyTime); result.put("skippedNoBuyTime", skippedNoBuyTime);
if (ok) { if (ok) {
@@ -481,6 +527,78 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
} }
} }
/**
* 按外部订单 id主键插入或更新同批重复 id 保留最后一条。
*
* @return 实际 upsert 条数;无有效 id 时返回 0失败返回 -1
*/
private int upsertBatch(List<LbOrderRow> entities) {
if (entities == null || entities.isEmpty()) {
return 0;
}
Map<Long, LbOrderRow> deduped = new LinkedHashMap<>();
for (LbOrderRow entity : entities) {
if (entity.getId() != null) {
deduped.put(entity.getId(), entity);
}
}
if (deduped.isEmpty()) {
return 0;
}
List<LbOrderRow> rows = new ArrayList<>(deduped.values());
try {
baseMapper.upsertBatch(rows);
return rows.size();
} catch (Exception e) {
log.error("lb_order_row upsertBatch failed, size={}", rows.size(), e);
return -1;
}
}
/**
* 按 seller_id 关联 lb_department_user.user_id用部门用户的 name、phone 填充卖方姓名与电话。
*/
private void fillSellerInfoFromDepartmentUsers(List<LbOrderRow> entities, String tenantId) {
if (entities == null || entities.isEmpty()) {
return;
}
Set<Long> sellerIds = new HashSet<>();
for (LbOrderRow entity : entities) {
if (entity.getSellerId() != null) {
sellerIds.add(entity.getSellerId());
}
}
if (sellerIds.isEmpty()) {
return;
}
List<String> userIdStrs = new ArrayList<>(sellerIds.size());
for (Long sellerId : sellerIds) {
userIdStrs.add(String.valueOf(sellerId));
}
LambdaQueryWrapper<LbDepartmentUser> w = new LambdaQueryWrapper<>();
w.eq(LbDepartmentUser::getTenantId, tenantId)
.in(LbDepartmentUser::getUserId, userIdStrs)
.orderByDesc(LbDepartmentUser::getUpdateTime)
.orderByDesc(LbDepartmentUser::getCreateTime);
List<LbDepartmentUser> users = lbDepartmentUserService.list(w);
Map<String, LbDepartmentUser> byUserId = new LinkedHashMap<>();
for (LbDepartmentUser user : users) {
if (user.getUserId() != null && !byUserId.containsKey(user.getUserId())) {
byUserId.put(user.getUserId(), user);
}
}
for (LbOrderRow entity : entities) {
if (entity.getSellerId() == null) {
continue;
}
LbDepartmentUser user = byUserId.get(String.valueOf(entity.getSellerId()));
if (user != null) {
entity.setSellerName(user.getName());
entity.setSellerPhone(user.getPhone());
}
}
}
private static LbOrderRow toLbOrderRow(HxrOrderRow row, String tenantId) { private static LbOrderRow toLbOrderRow(HxrOrderRow row, String tenantId) {
LbOrderRow e = new LbOrderRow(); LbOrderRow e = new LbOrderRow();
e.setId(row.id()); e.setId(row.id());
@@ -491,6 +609,8 @@ public class LbOrderRowServiceImpl extends ServiceImpl<LbOrderRowMapper, LbOrder
e.setTodayOrderCount(0); e.setTodayOrderCount(0);
e.setTodayUnresellCount(0); e.setTodayUnresellCount(0);
e.setSellerId(row.sellerId()); e.setSellerId(row.sellerId());
e.setSellerName(row.sellerName());
e.setSellerPhone(row.sellerPhone());
e.setBuyerId(row.buyerId()); e.setBuyerId(row.buyerId());
e.setOrderSn(row.orderSn()); e.setOrderSn(row.orderSn());
e.setTotalMoney(parseMoney(row.totalMoney())); e.setTotalMoney(parseMoney(row.totalMoney()));

View File

@@ -600,7 +600,7 @@ public class LbPurchaseApplyServiceImpl
continue; continue;
} }
try { try {
LocalDateTime vipTime = HxrAdminUserService.computeVipExpireTime(row.getApplyDate(), 3); LocalDateTime vipTime = HxrAdminUserService.computeVipExpireTime(row.getApplyDate(), 2);
String vipTimeStr = HxrAdminUserService.formatVipTime(vipTime); String vipTimeStr = HxrAdminUserService.formatVipTime(vipTime);
one.put("viptime", vipTimeStr); one.put("viptime", vipTimeStr);
@@ -940,7 +940,6 @@ public class LbPurchaseApplyServiceImpl
.orderByAsc(LbPurchaseApply::getApplyDate) .orderByAsc(LbPurchaseApply::getApplyDate)
.orderByAsc(LbPurchaseApply::getId); .orderByAsc(LbPurchaseApply::getId);
List<LbPurchaseApply> rows = this.list(queryWrapper); List<LbPurchaseApply> rows = this.list(queryWrapper);
Map<String, Integer> maxOrderByColleaguePhone = loadColleagueMaxOrderCache(rows);
LinkedHashMap<LocalDate, List<LbPurchaseApply>> grouped = new LinkedHashMap<>(); LinkedHashMap<LocalDate, List<LbPurchaseApply>> grouped = new LinkedHashMap<>();
for (LbPurchaseApply row : rows) { for (LbPurchaseApply row : rows) {
@@ -983,7 +982,7 @@ public class LbPurchaseApplyServiceImpl
createExportCell(row, 2, nullToEmpty(item.getApplyUser()), dataStyle); createExportCell(row, 2, nullToEmpty(item.getApplyUser()), dataStyle);
createExportCell(row, 3, nullToEmpty(item.getApplyPhone()), dataStyle); createExportCell(row, 3, nullToEmpty(item.getApplyPhone()), dataStyle);
createExportCell(row, 4, formatPrivilegeRange(item), dataStyle); createExportCell(row, 4, formatPrivilegeRange(item), dataStyle);
createExportCell(row, 5, formatRecommender(item, maxOrderByColleaguePhone), dataStyle); createExportCell(row, 5, formatRecommender(item), dataStyle);
createExportCell(row, 6, nullToEmpty(item.getColleaguePhone()), dataStyle); createExportCell(row, 6, nullToEmpty(item.getColleaguePhone()), dataStyle);
createExportCell(row, 7, nullToEmpty(item.getTeamLeader()), dataStyle); createExportCell(row, 7, nullToEmpty(item.getTeamLeader()), dataStyle);
createExportCell(row, 8, formatActivationDate(item.getApplyDate()), dataStyle); createExportCell(row, 8, formatActivationDate(item.getApplyDate()), dataStyle);
@@ -1026,25 +1025,6 @@ public class LbPurchaseApplyServiceImpl
} }
} }
private Map<String, Integer> loadColleagueMaxOrderCache(List<LbPurchaseApply> rows) {
Map<String, Integer> cache = new HashMap<>();
Set<String> phones = new HashSet<>();
for (LbPurchaseApply row : rows) {
if (row.getColleaguePhone() != null && !row.getColleaguePhone().trim().isEmpty()) {
phones.add(row.getColleaguePhone().trim());
}
}
for (String phone : phones) {
try {
Optional<HxrUserRow> userOpt = hxrAdminUserService.fetchFirstUserByMobile(phone);
userOpt.map(HxrUserRow::maxOrder).ifPresent(maxOrder -> cache.put(phone, maxOrder));
} catch (Exception ex) {
log.debug("导出时查询推荐人 max_order 失败phone={}", phone, ex);
}
}
return cache;
}
private static String formatDatePeopleLabel(LocalDate applyDate, int count) { private static String formatDatePeopleLabel(LocalDate applyDate, int count) {
if (applyDate == null || applyDate.equals(LocalDate.MIN)) { if (applyDate == null || applyDate.equals(LocalDate.MIN)) {
return "未知日期招商" + count + ""; return "未知日期招商" + count + "";
@@ -1062,20 +1042,12 @@ public class LbPurchaseApplyServiceImpl
return start.format(PRIVILEGE_RANGE_FMT) + "" + endDate.format(PRIVILEGE_RANGE_FMT); return start.format(PRIVILEGE_RANGE_FMT) + "" + endDate.format(PRIVILEGE_RANGE_FMT);
} }
private static String formatRecommender(LbPurchaseApply item, Map<String, Integer> maxOrderByPhone) { private static String formatRecommender(LbPurchaseApply item) {
String name = item.getColleagueName(); String name = item.getColleagueName();
if (name == null || name.trim().isEmpty()) { if (name == null || name.trim().isEmpty()) {
return ""; return "";
} }
String trimmedName = name.trim(); return name.trim();
String phone = item.getColleaguePhone() == null ? "" : item.getColleaguePhone().trim();
if (!phone.isEmpty()) {
Integer maxOrder = maxOrderByPhone.get(phone);
if (maxOrder != null) {
return trimmedName + " " + maxOrder;
}
}
return trimmedName;
} }
private static String formatActivationDate(LocalDate applyDate) { private static String formatActivationDate(LocalDate applyDate) {

View File

@@ -15,7 +15,9 @@ app:
# hxrd 后台订单列表LBAdminPullScheduler每 50 分钟一次,仅工作日 18:1023:59:59 执行,周末不跑)。默认关闭。 # hxrd 后台订单列表LBAdminPullScheduler每 50 分钟一次,仅工作日 18:1023:59:59 执行,周末不跑)。默认关闭。
hxr: hxr:
admin: admin:
enabled: false enabled: true
# 未支付订单定时同步写入 lb_order_row 的租户 idLBAdminPullScheduler#pullOrdersForUnPay
sync-tenant-id: "TENANT_ID_CST_2026"
# 首次拉单延迟毫秒0 表示启动后尽快执行;集成测试会设为较大值避免与用例并发 # 首次拉单延迟毫秒0 表示启动后尽快执行;集成测试会设为较大值避免与用例并发
pull-initial-delay-ms: 0 pull-initial-delay-ms: 0
cookie: PHPSID=f3710baf6381da418aa832660ccb9d08 cookie: PHPSID=f3710baf6381da418aa832660ccb9d08

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rj.mapper.LbOrderRowMapper">
<!-- 外部订单 id 为全局主键,按 id upsert不受多租户拦截器影响 -->
<insert id="upsertBatch">
INSERT INTO lb_order_row (
id, old_id, tenant_id, data_type,
seller_id, seller_name, seller_phone,
buyer_id, order_sn, total_money,
pay_time, pay_img, status, is_resell, is_show,
consignee, phone, province, city, area, address,
merchandise_id, confirm_time, buy_time, created_at, updated_at,
today_total_money_sum, today_unresell_count, today_order_count
) VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.id}, #{item.oldId}, #{item.tenantId}, #{item.dataType},
#{item.sellerId}, #{item.sellerName}, #{item.sellerPhone},
#{item.buyerId}, #{item.orderSn}, #{item.totalMoney},
#{item.payTime}, #{item.payImg}, #{item.status}, #{item.isResell}, #{item.isShow},
#{item.consignee}, #{item.phone}, #{item.province}, #{item.city}, #{item.area}, #{item.address},
#{item.merchandiseId}, #{item.confirmTime}, #{item.buyTime}, #{item.createdAt}, #{item.updatedAt},
#{item.todayTotalMoneySum}, #{item.todayUnresellCount}, #{item.todayOrderCount}
)
</foreach>
ON DUPLICATE KEY UPDATE
old_id = VALUES(old_id),
tenant_id = VALUES(tenant_id),
data_type = VALUES(data_type),
seller_id = VALUES(seller_id),
seller_name = VALUES(seller_name),
seller_phone = VALUES(seller_phone),
buyer_id = VALUES(buyer_id),
order_sn = VALUES(order_sn),
total_money = VALUES(total_money),
pay_time = VALUES(pay_time),
pay_img = VALUES(pay_img),
status = VALUES(status),
is_resell = VALUES(is_resell),
is_show = VALUES(is_show),
consignee = VALUES(consignee),
phone = VALUES(phone),
province = VALUES(province),
city = VALUES(city),
area = VALUES(area),
address = VALUES(address),
merchandise_id = VALUES(merchandise_id),
confirm_time = VALUES(confirm_time),
buy_time = VALUES(buy_time),
created_at = VALUES(created_at),
updated_at = VALUES(updated_at),
today_total_money_sum = VALUES(today_total_money_sum),
today_unresell_count = VALUES(today_unresell_count),
today_order_count = VALUES(today_order_count)
</insert>
</mapper>

View File

@@ -0,0 +1,9 @@
-- =============================================================================
-- 升级脚本:为 lb_order_row 表增加 seller_name、seller_phone 列
-- =============================================================================
SET NAMES utf8mb4;
ALTER TABLE `lb_order_row`
ADD COLUMN `seller_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '卖家姓名' AFTER `seller_id`,
ADD COLUMN `seller_phone` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '卖家电话' AFTER `seller_name`;