diff --git a/src/main/java/cn/van/business/mq/MessageConsumerService.java b/src/main/java/cn/van/business/mq/MessageConsumerService.java index eb068ac..5a3563e 100644 --- a/src/main/java/cn/van/business/mq/MessageConsumerService.java +++ b/src/main/java/cn/van/business/mq/MessageConsumerService.java @@ -25,12 +25,12 @@ import static cn.van.business.util.WXUtil.WX_BASE_URL; * @description: */ @Service -@RocketMQMessageListener(topic = "wx-message", consumerGroup = "${rocketmq.consumer.group}", nameServer = "${rocketmq.name-server}", consumeMode = ConsumeMode.ORDERLY // 顺序消费(单线程) +@RocketMQMessageListener(topic = "wx-message", consumerGroup = "${rocketmq.consumer.group}", nameServer = "${rocketmq.name-server}" ) public class MessageConsumerService implements RocketMQListener { private static final Logger logger = LoggerFactory.getLogger(MessageConsumerService.class); - private static final RateLimiter rateLimiter = RateLimiter.create(0.5, // 1 QPS + private static final RateLimiter rateLimiter = RateLimiter.create(2, // 1 QPS 5, // 预热期 5 秒 TimeUnit.SECONDS); diff --git a/src/main/java/cn/van/business/repository/OrderRowRepository.java b/src/main/java/cn/van/business/repository/OrderRowRepository.java index 535aae0..3a8c482 100644 --- a/src/main/java/cn/van/business/repository/OrderRowRepository.java +++ b/src/main/java/cn/van/business/repository/OrderRowRepository.java @@ -8,8 +8,11 @@ package cn.van.business.repository; */ import cn.van.business.model.jd.OrderRow; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Repository; @@ -31,11 +34,16 @@ public interface OrderRowRepository extends JpaRepository { // 查找 validCode != 15 或者 !=-1 的订单行 ,并且按orderTime 降序 @Query("select o from OrderRow o where o.validCode not in ?1 and o.unionId =?2 order by o.orderTime DESC") - List findByValidCodeNotInOrderByOrderTimeDescAndUnionId(int[] validCodes,Long unionId); + List findByValidCodeNotInOrderByOrderTimeDescAndUnionId(int[] validCodes, Long unionId); @Query("select o from OrderRow o where o.validCode not in ?1 and o.orderTime >= ?2 order by o.orderTime DESC") - List findByValidCodeNotInAndOrderTimeGreaterThanOrderByOrderTimeDesc( - int[] validCodes, - @DateTimeFormat(pattern = "yyyy-MM-dd") Date threeMonthsAgo - ); + List findByValidCodeNotInAndOrderTimeGreaterThanOrderByOrderTimeDesc(int[] validCodes, @DateTimeFormat(pattern = "yyyy-MM-dd") Date threeMonthsAgo); + + @Query("select o from OrderRow o where o.validCode not in ?1 and o.skuId = ?2 and o.unionId = ?3 order by o.orderTime DESC") + List findBySkuIdAndUnionId(int[] validCodes,long skuId, long unionId); + + //// 在OrderRowRepository中添加模糊查询方法 + //// 模糊查询收件人姓名或地址(包含分页) + //@Query("SELECT o FROM OrderRow o WHERE " + "o.recipientName LIKE %:keyword% OR " + "o.address LIKE %:keyword% " + "ORDER BY o.orderTime DESC") + //Page searchByRecipientOrAddress(@Param("keyword") String keyword, Pageable pageable); } diff --git a/src/main/java/cn/van/business/util/JDUtil.java b/src/main/java/cn/van/business/util/JDUtil.java index d11a094..c742f86 100644 --- a/src/main/java/cn/van/business/util/JDUtil.java +++ b/src/main/java/cn/van/business/util/JDUtil.java @@ -5,6 +5,7 @@ import cn.van.business.model.jd.OrderRow; import cn.van.business.model.jd.ProductOrder; import cn.van.business.repository.OrderRowRepository; import cn.van.business.repository.ProductOrderRepository; +import cn.van.business.util.jdReq.*; import com.alibaba.fastjson2.util.DateUtils; import com.fasterxml.jackson.databind.ObjectMapper; import com.jd.open.api.sdk.DefaultJdClient; @@ -16,15 +17,11 @@ import com.jd.open.api.sdk.request.kplunion.UnionOpenOrderRowQueryRequest; import com.jd.open.api.sdk.request.kplunion.UnionOpenPromotionBysubunionidGetRequest; import com.jd.open.api.sdk.response.kplunion.UnionOpenOrderRowQueryResponse; import com.jd.open.api.sdk.response.kplunion.UnionOpenPromotionBysubunionidGetResponse; -import io.github.resilience4j.core.functions.CheckedRunnable; -import io.github.resilience4j.ratelimiter.RateLimiter; -import io.github.resilience4j.ratelimiter.RequestNotPermitted; import lombok.Getter; import lombok.Setter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.annotation.Scheduled; @@ -78,52 +75,41 @@ public class JDUtil { private static final Logger logger = LoggerFactory.getLogger(JDUtil.class); private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final String INTERACTION_STATE_PREFIX = "interaction_state:"; + private static final long TIMEOUT_MINUTES = 1; private final StringRedisTemplate redisTemplate; private final OrderRowRepository orderRowRepository; private final ProductOrderRepository productOrderRepository; private final WXUtil wxUtil; private final OrderUtil orderUtil; - private static final String INTERACTION_STATE_PREFIX = "interaction_state:"; - private static final long TIMEOUT_MINUTES = 1; + // 添加ObjectMapper来序列化和反序列化UserInteractionState + private final ObjectMapper objectMapper = new ObjectMapper(); // 构造函数中注入StringRedisTemplate @Autowired - public JDUtil(StringRedisTemplate redisTemplate, - ProductOrderRepository productOrderRepository, - OrderRowRepository orderRowRepository, WXUtil wxUtil, - OrderUtil orderUtil) { - this.redisTemplate = redisTemplate; + public JDUtil(StringRedisTemplate redisTemplate, ProductOrderRepository productOrderRepository, OrderRowRepository orderRowRepository, WXUtil wxUtil, OrderUtil orderUtil) { + this.redisTemplate = redisTemplate; this.orderRowRepository = orderRowRepository; this.productOrderRepository = productOrderRepository; this.wxUtil = wxUtil; this.orderUtil = orderUtil; } - // 定义一个内部类来存储用户交互状态 -@Getter -@Setter -private static class UserInteractionState { - private String lastInteractionTime; - private String currentState; - private Map collectedFields; // 用于存储收集到的字段值 - private String currentField; // 当前正在询问的字段 + private static List filterOrdersByDate(List orderRows, int daysBack) { + LocalDate now = LocalDate.now(); - public UserInteractionState() { - this.lastInteractionTime = LocalDateTime.now().format(DATE_TIME_FORMATTER); - this.currentState = "INIT"; - this.collectedFields = new HashMap<>(); - this.currentField = null; + return orderRows.stream().filter(order -> { + // 将 Date 转换为 LocalDate + LocalDate orderDate = order.getOrderTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + + // 计算是否在给定的天数内 + return !orderDate.isBefore(now.minusDays(daysBack)) && !orderDate.isAfter(now); + }).collect(Collectors.toList()); } - public void updateLastInteractionTime() { - this.lastInteractionTime = LocalDateTime.now().format(DATE_TIME_FORMATTER); + private static Stream getStreamForWeiGui(List todayOrders) { + return todayOrders.stream().filter(orderRow -> orderRow.getValidCode() == 13 || orderRow.getValidCode() == 25 || orderRow.getValidCode() == 26 || orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28 || orderRow.getValidCode() == 29); } -} - - - // 添加ObjectMapper来序列化和反序列化UserInteractionState - private final ObjectMapper objectMapper = new ObjectMapper(); - /** * 将 响应参数转化为 OrderRow,并返回 @@ -200,93 +186,86 @@ private static class UserInteractionState { return orderRow; } - private static List filterOrdersByDate(List orderRows, int daysBack) { - LocalDate now = LocalDate.now(); + public int fetchOrders(OrderFetchStrategy strategy, String appKey, String secretKey) { + TimeRange range = strategy.calculateRange(LocalDateTime.now()); + int count = 0; - return orderRows.stream().filter(order -> { - // 将 Date 转换为 LocalDate - LocalDate orderDate = order.getOrderTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + // 复用原有的抓取逻辑 + LocalDateTime current = range.getStart(); + while (!current.isAfter(range.getEnd())) { + // 调用分页抓取API... + Integer pageIndex = 1; + boolean hasMore = true; - // 计算是否在给定的天数内 - return !orderDate.isBefore(now.minusDays(daysBack)) && !orderDate.isAfter(now); - }).collect(Collectors.toList()); - } - - private static Stream getStreamForWeiGui(List todayOrders) { - return todayOrders.stream().filter(orderRow -> orderRow.getValidCode() == 13 || orderRow.getValidCode() == 25 || orderRow.getValidCode() == 26 || orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28 || orderRow.getValidCode() == 29); - } - -/** - * 实时刷新最近10分钟的订单(Resilience4j限流集成) - */ -@Scheduled(cron = "0 * * * * ?") -public void fetchLatestOrder() { - try { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime lastMinute = now.minusMinutes(10).withSecond(0).withNano(0); - - for (Map.Entry entry : super_admins.entrySet()) { - WXUtil.SuperAdmin admin = entry.getValue(); - String appKey = admin.getAppKey(); - String secretKey = admin.getSecretKey(); - - if (Util.isAnyEmpty(appKey, secretKey)) { - continue; - } - // 如果当前分钟数刚好是整10,就打印 - if (now.getMinute() % 10 == 0) { - logger.info("实时订单 {} ", appKey.substring(appKey.length() - 4)); - } - UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime( - lastMinute, true, 1, true, appKey, secretKey - ); - - if (response != null && response.getQueryResult() != null - && response.getQueryResult().getCode() == 200) { - OrderRowResp[] orderRowResps = response.getQueryResult().getData(); - if (orderRowResps == null) continue; - - Arrays.stream(orderRowResps) - .map(this::createOrderRow) - .forEach(orderRowRepository::save); + while (hasMore) { + try { + // 30-60 天 ,非实时,非分钟 + UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime(current, false, pageIndex, false, appKey, secretKey); + if (response != null && response.getQueryResult() != null) { + if (response.getQueryResult().getCode() == 200) { + OrderRowResp[] orderRowResps = response.getQueryResult().getData(); + if (orderRowResps != null) { + for (OrderRowResp orderRowResp : orderRowResps) { + if (orderRowResp != null) { // Check each orderRowResp is not null + OrderRow orderRow = createOrderRow(orderRowResp); + if (orderRow != null) { // Ensure orderRow is not null after creation + orderRowRepository.save(orderRow); + count++; + } + } + } + } + hasMore = Boolean.TRUE.equals(response.getQueryResult().getHasMore()); + } else { + hasMore = false; + } + } else { + hasMore = false; + } + } catch (Exception e) { + hasMore = false; // Optionally break out of the while loop if required } + if (hasMore) pageIndex++; } - } catch (Exception e) { - logger.error("调度任务异常", e); - } -} - - - - public void test01() { - - for (Map.Entry entry : super_admins.entrySet()) { - //String wxid = entry.getKey(); - WXUtil.SuperAdmin admin = entry.getValue(); - String appKey = admin.getAppKey(); - String secretKey = admin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - continue; - } - LocalDateTime now = LocalDateTime.now(); - //logger.info("拉取历史订单---> , {} 点,{} 分", now.getHour(), now.getMinute()); - - LocalDateTime lastHour = now.truncatedTo(ChronoUnit.HOURS); - LocalDateTime startDate = lastHour.minusMonths(12); - - logger.info("{} - {}", startDate, lastHour); - - while (!startDate.isEqual(lastHour)) { - - test(startDate, appKey); - logger.info("test {}", startDate); - - - startDate = startDate.plusHours(1); - } + current = current.plusHours(1); } + return count; } + /** + * 实时刷新最近10分钟的订单(Resilience4j限流集成) + */ + @Scheduled(cron = "0 * * * * ?") + public void fetchLatestOrder() { + LocalDateTime now = LocalDateTime.now(); + LocalDateTime startTime = now.minusMinutes(10).withSecond(0).withNano(0); + + super_admins.values().parallelStream().forEach(admin -> { + if (Util.isAnyEmpty(admin.getAppKey(), admin.getSecretKey())) return; + + try { + UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime(startTime, true, 1, true, admin.getAppKey(), admin.getSecretKey()); + + if (isValidResponse(response)) { + processOrderResponse(response, admin); + } + } catch (RateLimitExceededException e) { + logger.warn("[限流] {} 请求频率受限", admin.getAppKey().substring(18)); + } catch (Exception e) { + logger.error("{} 订单抓取异常: {}", admin.getAppKey().substring(18), e.getMessage()); + } + }); + } + + // 响应校验方法 + private boolean isValidResponse(UnionOpenOrderRowQueryResponse response) { + return response != null && response.getQueryResult() != null && response.getQueryResult().getCode() == 200 && response.getQueryResult().getData() != null; + } + + // 订单处理方法 + private void processOrderResponse(UnionOpenOrderRowQueryResponse response, WXUtil.SuperAdmin admin) { + Arrays.stream(response.getQueryResult().getData()).parallel().map(this::createOrderRow).forEach(orderRowRepository::save); + } /** * 扫描订单发送到微信 @@ -315,71 +294,18 @@ public void fetchLatestOrder() { */ @Scheduled(cron = "0 0 */4 * * ?") public void fetchHistoricalOrders3090() { - try { - for (Map.Entry entry : super_admins.entrySet()) { - //String wxid = entry.getKey(); - WXUtil.SuperAdmin admin = entry.getValue(); - String appKey = admin.getAppKey(); - String secretKey = admin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - continue; - } - fetchHistoricalOrders3090Do(appKey, secretKey); - } - } catch (Exception e) { - logger.error("拉取历史订单3090异常", e); - } - - } - - private int fetchHistoricalOrders3090Do(String appKey, String secretKey) { - - int count = 0; - LocalDateTime now = LocalDateTime.now(); - //logger.info("拉取历史订单---> , {} 点,{} 分", now.getHour(), now.getMinute()); - - LocalDateTime lastHour = now.truncatedTo(ChronoUnit.HOURS).minusMonths(1); - LocalDateTime startDate = lastHour.minusMonths(3).truncatedTo(ChronoUnit.HOURS); - - - while (!startDate.isEqual(lastHour)) { - Integer pageIndex = 1; - boolean hasMore = true; - - while (hasMore) { + OrderFetchStrategy strategy = new Days3090Strategy(); + for (WXUtil.SuperAdmin admin : super_admins.values()) { try { - // 30-60 天 ,非实时,非分钟 - UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime(startDate, false, pageIndex, false, appKey, secretKey); - if (response != null && response.getQueryResult() != null) { - if (response.getQueryResult().getCode() == 200) { - OrderRowResp[] orderRowResps = response.getQueryResult().getData(); - if (orderRowResps != null) { - for (OrderRowResp orderRowResp : orderRowResps) { - if (orderRowResp != null) { // Check each orderRowResp is not null - OrderRow orderRow = createOrderRow(orderRowResp); - if (orderRow != null) { // Ensure orderRow is not null after creation - orderRowRepository.save(orderRow); - count++; - } - } - } - } - hasMore = Boolean.TRUE.equals(response.getQueryResult().getHasMore()); - } else { - hasMore = false; - } - } else { - hasMore = false; - } + fetchOrders(strategy, admin.getAppKey(), admin.getSecretKey()); } catch (Exception e) { - hasMore = false; // Optionally break out of the while loop if required + logger.error("账号{}拉取异常: {}", admin.getAppKey().substring(18), e.getMessage()); } - if (hasMore) pageIndex++; } - startDate = startDate.plusHours(1); + } catch (Exception ex) { + logger.error("策略执行异常", ex); } - return count; } /** @@ -388,67 +314,17 @@ public void fetchLatestOrder() { @Scheduled(cron = "0 0 * * * ?") public void fetchHistoricalOrders1430() { try { - for (Map.Entry entry : super_admins.entrySet()) { - //String wxid = entry.getKey(); - WXUtil.SuperAdmin admin = entry.getValue(); - String appKey = admin.getAppKey(); - String secretKey = admin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - continue; - } - fetchHistoricalOrders1430Do(appKey, secretKey); - } - }catch (Exception e){ - logger.error("拉取历史订单1430异常", e); - } - - } - - private int fetchHistoricalOrders1430Do(String appKey, String secretKey) { - int count = 0; - LocalDateTime now = LocalDateTime.now(); - //logger.info("拉取历史订单---> , {} 点,{} 分", now.getHour(), now.getMinute()); - - LocalDateTime lastHour = now.truncatedTo(ChronoUnit.HOURS).minusDays(14); - LocalDateTime startDate = lastHour.minusMonths(1).truncatedTo(ChronoUnit.HOURS); - - while (!startDate.isEqual(lastHour)) { - Integer pageIndex = 1; - boolean hasMore = true; - - while (hasMore) { + OrderFetchStrategy strategy = new Days1430Strategy(); // 需补充Days1430Strategy实现 + for (WXUtil.SuperAdmin admin : super_admins.values()) { try { - // 14 - 30 天 ,非实时,非分钟 - UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime(startDate, false, pageIndex, false, appKey, secretKey); - if (response != null && response.getQueryResult() != null) { - if (response.getQueryResult().getCode() == 200) { - OrderRowResp[] orderRowResps = response.getQueryResult().getData(); - if (orderRowResps != null) { - for (OrderRowResp orderRowResp : orderRowResps) { - if (orderRowResp != null) { // Check each orderRowResp is not null - OrderRow orderRow = createOrderRow(orderRowResp); - if (orderRow != null) { // Ensure orderRow is not null after creation - orderRowRepository.save(orderRow); - count++; - } - } - } - } - hasMore = Boolean.TRUE.equals(response.getQueryResult().getHasMore()); - } else { - hasMore = false; - } - } else { - hasMore = false; - } + fetchOrders(strategy, admin.getAppKey(), admin.getSecretKey()); } catch (Exception e) { - hasMore = false; // Optionally break out of the while loop if required + logger.error("账号{}拉取异常: {}", admin.getAppKey().substring(18), e.getMessage()); } - if (hasMore) pageIndex++; } - startDate = startDate.plusHours(1); + } catch (Exception ex) { + logger.error("1430策略执行异常", ex); } - return count; } /** @@ -457,132 +333,42 @@ public void fetchLatestOrder() { @Scheduled(cron = "0 0 * * * ?") public void fetchHistoricalOrders0714() { try { - for (Map.Entry entry : super_admins.entrySet()) { - //String wxid = entry.getKey(); - WXUtil.SuperAdmin admin = entry.getValue(); - String appKey = admin.getAppKey(); - String secretKey = admin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - continue; - } - fetchHistoricalOrders0714Do(appKey, secretKey); - } - }catch (Exception e){ - logger.error("拉取历史订单0714异常", e); - } - - } - - private int fetchHistoricalOrders0714Do(String appKey, String secretKey) { - int count = 0; - LocalDateTime now = LocalDateTime.now(); - //logger.info("拉取历史订单---> , {} 点,{} 分", now.getHour(), now.getMinute()); - LocalDateTime lastHour = now.truncatedTo(ChronoUnit.HOURS).minusDays(7); - LocalDateTime startDate = lastHour.minusDays(14).truncatedTo(ChronoUnit.HOURS); - - while (!startDate.isEqual(lastHour)) { - Integer pageIndex = 1; - boolean hasMore = true; - - while (hasMore) { + OrderFetchStrategy strategy = new Days0714Strategy(); + super_admins.values().parallelStream().forEach(admin -> { + if (Util.isAnyEmpty(admin.getAppKey(), admin.getSecretKey())) return; try { - // 7 - 14 天 ,非实时,非分钟 - UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime(startDate, false, pageIndex, false, appKey, secretKey); - if (response != null && response.getQueryResult() != null) { - if (response.getQueryResult().getCode() == 200) { - OrderRowResp[] orderRowResps = response.getQueryResult().getData(); - if (orderRowResps != null) { - for (OrderRowResp orderRowResp : orderRowResps) { - if (orderRowResp != null) { // Check each orderRowResp is not null - OrderRow orderRow = createOrderRow(orderRowResp); - if (orderRow != null) { // Ensure orderRow is not null after creation - orderRowRepository.save(orderRow); - count++; - } - } - } - } - hasMore = Boolean.TRUE.equals(response.getQueryResult().getHasMore()); - } else { - hasMore = false; - } - } else { - hasMore = false; - } + fetchOrders(strategy, admin.getAppKey(), admin.getSecretKey()); } catch (Exception e) { - hasMore = false; // Optionally break out of the while loop if required + logger.error("账号{}0714拉取异常: {}", admin.getAppKey().substring(18), e.getMessage()); } - if (hasMore) pageIndex++; - } - startDate = startDate.plusHours(1); + }); + } catch (Exception ex) { + logger.error("0714策略执行异常", ex); } - return count; + } @Scheduled(cron = "0 */5 * * * ?") public void fetchHistoricalOrders0007() { try { - for (Map.Entry entry : super_admins.entrySet()) { - //String wxid = entry.getKey(); - WXUtil.SuperAdmin admin = entry.getValue(); - String appKey = admin.getAppKey(); - String secretKey = admin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - continue; - } - fetchHistoricalOrders0007Do(appKey, secretKey); - } - }catch (Exception e){ - logger.error("拉取历史订单0007异常", e); - } + OrderFetchStrategy strategy = new Days0007Strategy(); + super_admins.values().parallelStream().forEach(admin -> { + if (Util.isAnyEmpty(admin.getAppKey(), admin.getSecretKey())) return; - } - - private int fetchHistoricalOrders0007Do(String appKey, String secretKey) { - - int count = 0; - LocalDateTime now = LocalDateTime.now(); - //logger.info("拉取历史订单---> , {} 点,{} 分", now.getHour(), now.getMinute()); - LocalDateTime lastHour = now.truncatedTo(ChronoUnit.HOURS); - LocalDateTime startDate = lastHour.minusDays(7).truncatedTo(ChronoUnit.HOURS); - - while (!startDate.isEqual(lastHour)) { - Integer pageIndex = 1; - boolean hasMore = true; - - while (hasMore) { try { - // 0 - 7 天 ,非实时,非分钟 - UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime(startDate, false, pageIndex, false, appKey, secretKey); - if (response != null && response.getQueryResult() != null) { - if (response.getQueryResult().getCode() == 200) { - OrderRowResp[] orderRowResps = response.getQueryResult().getData(); - if (orderRowResps != null) { - for (OrderRowResp orderRowResp : orderRowResps) { - if (orderRowResp != null) { // Check each orderRowResp is not null - OrderRow orderRow = createOrderRow(orderRowResp); - if (orderRow != null) { // Ensure orderRow is not null after creation - orderRowRepository.save(orderRow); - count++; - } - } - } - } - hasMore = Boolean.TRUE.equals(response.getQueryResult().getHasMore()); - } else { - hasMore = false; - } - } else { - hasMore = false; - } + int count = fetchOrders(strategy, admin.getAppKey(), admin.getSecretKey()); + + logger.info("账号{} 0007订单拉取完成,新增{}条", admin.getAppKey().substring(18), count); + } catch (RateLimitExceededException e) { + logger.warn("[限流] {} 0007请求受限", admin.getAppKey().substring(18)); } catch (Exception e) { - hasMore = false; // Optionally break out of the while loop if required + logger.error("账号{}0007拉取异常: {}", admin.getAppKey().substring(18), e.getMessage()); } - if (hasMore) pageIndex++; - } - startDate = startDate.plusHours(1); + }); + } catch (Exception ex) { + logger.error("0007策略执行异常", ex); } - return count; + } /** @@ -624,8 +410,7 @@ public void fetchLatestOrder() { // 打印方法调用和开始结束时间 if (isRealTime && (LocalDateTime.now().getMinute() % 10 == 0)) { - - logger.info(" {} --- 拉取订单, 分钟还是秒 {} , 开始时间:{} --- 结束时间:{}", appKey.substring(appKey.length() - 4), hourMinuteTag, startTime.format(DATE_TIME_FORMATTER), endTime.format(DATE_TIME_FORMATTER)); + logger.debug(" {} --- 拉取订单, 分钟还是秒 {} , 开始时间:{} --- 结束时间:{}", appKey.substring(appKey.length() - 4), hourMinuteTag, startTime.format(DATE_TIME_FORMATTER), endTime.format(DATE_TIME_FORMATTER)); } return unionOpenOrderRowQueryResponse; @@ -636,35 +421,18 @@ public void fetchLatestOrder() { } - public synchronized void test(LocalDateTime startTime, String appKey) { - String oldTimeTag = JD_REFRESH_TAG + startTime.format(DATE_TIME_FORMATTER); - String newTimeTag = JD_REFRESH_TAG + appKey + ":" + startTime.format(DATE_TIME_FORMATTER); - - - HashOperations hashOps = redisTemplate.opsForHash(); - -// get all entries from the old hash - Map entries = hashOps.entries(oldTimeTag); - -// put all entries into the new hash - hashOps.putAll(newTimeTag, entries); - - logger.info("oldTimeTag {} 复制 到 newTimeTag {} ", oldTimeTag, newTimeTag); -// delete the old hash -// redisTemplate.delete(oldTimeTag); + public void sendOrderToWxByOrderDefault(String order, String fromWxid) { + logger.info("执行 sendOrderToWxByOrderDefault 方法,order: {}, fromWxid: {}", order, fromWxid); + handleUserInteraction(fromWxid, order); + // 具体逻辑 } -public void sendOrderToWxByOrderDefault(String order, String fromWxid) { - logger.info("执行 sendOrderToWxByOrderDefault 方法,order: {}, fromWxid: {}", order, fromWxid); - handleUserInteraction(fromWxid, order); - // 具体逻辑 -} /** * 接收京粉指令指令 */ public void sendOrderToWxByOrderJD(String order, String fromWxid) { - int[] param = {-1}; + int[] param = {-1}; WXUtil.SuperAdmin superAdmin = super_admins.get(fromWxid); String unionId = superAdmin.getUnionId(); List orderRows = orderRowRepository.findByValidCodeNotInOrderByOrderTimeDescAndUnionId(param, Long.valueOf(unionId)); @@ -677,9 +445,11 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { * 今天订单 * 昨天订单 * */ + List contents = new ArrayList<>(); StringBuilder content = new StringBuilder(); switch (order) { case "菜单": + content.append("菜单:京+命令 \n 如: 京今日统计\r"); content.append("今日统计\r"); content.append("昨天统计\r"); @@ -693,23 +463,24 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("今日订单\r"); content.append("昨日订单\r"); content.append("刷新7天\r"); - content.append("刷新3090\r"); - content.append("刷新1430\r"); - content.append("刷新0714\r"); - content.append("\n"); - content.append(":::高级菜单:::\r"); - content.append("菜单:京+高级+命令 \n 如: 京高级违规30\r"); - content.append("京高级违规+整数\r"); - content.append("京高级+订单号\r\""); - content.append("京高级SKU+sku\\r\""); - content.append("京高级搜索+搜索标题,只返回最近10条\r\""); + contents.add(content); + content = new StringBuilder(); + + content.append("高级菜单:京+高级+命令 \n 如: 京高级违规30\r"); + content.append("京高级违规+整数(不传数字为365天)\r"); + content.append("京高级SKU+sku\r"); + content.append("京高级搜索+搜索标题(精准查询订单号+精准查询sku+模糊查询收件人+模糊查询地址),只返回最近100条\r"); + + contents.add(content); break; case "测试指令": { //test01(); break; } case "今日统计": { + content = new StringBuilder(); + List todayOrders = filterOrdersByDate(orderRows, 0); // 订单总数,已付款,已取消,佣金总计 content.append("今日统计:\n"); @@ -722,9 +493,12 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已完成佣金:").append(todayOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(todayOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + contents.add(content); break; } case "已付款": { + content = new StringBuilder(); + List yfkOrders = orderRows.stream().filter(orderRow -> orderRow.getValidCode() == 16).collect(Collectors.toList()); content.append("已付款:\n"); content.append("订单总数:").append(yfkOrders.size()).append("\r"); @@ -732,12 +506,15 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { for (OrderRow orderRow : yfkOrders) { orderUtil.orderToWx(orderRow, false); } + contents.add(content); + break; } case "昨日统计": { } case "三日统计": { + content = new StringBuilder(); List last3DaysOrders = filterOrdersByDate(orderRows, 3); content.append("三日统计:\n"); content.append("订单总数:").append(last3DaysOrders.size()).append("\r"); @@ -748,9 +525,12 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(last3DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(last3DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(last3DaysOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } case "七日统计": { + content = new StringBuilder(); List last7DaysOrders = filterOrdersByDate(orderRows, 7); content.append("七日统计:\n"); content.append("订单总数:").append(last7DaysOrders.size()).append("\r"); @@ -761,9 +541,12 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(last7DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(last7DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(last7DaysOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } case "一个月统计": { + content = new StringBuilder(); List last30DaysOrders = filterOrdersByDate(orderRows, 30); content.append("一个月统计:\n"); content.append("订单总数:").append(last30DaysOrders.size()).append("\r"); @@ -774,9 +557,13 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(last30DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(last30DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(last30DaysOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } case "两个月统计": { + + content = new StringBuilder(); List last60DaysOrders = filterOrdersByDate(orderRows, 60); content.append("两个月统计:\n"); content.append("订单总数:").append(last60DaysOrders.size()).append("\r"); @@ -787,9 +574,13 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(last60DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(last60DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(last60DaysOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } case "三个月统计": { + + content = new StringBuilder(); List last90DaysOrders = filterOrdersByDate(orderRows, 90); content.append("订单总数:").append(last90DaysOrders.size()).append("\r"); content.append("已付款:").append(last90DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).count()).append("\r"); @@ -799,9 +590,13 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(last90DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(last90DaysOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(last90DaysOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } case "这个月统计": { + + content = new StringBuilder(); // 计算出距离1号有几天 int days = LocalDate.now().getDayOfMonth(); List thisMonthOrders = filterOrdersByDate(orderRows, days); @@ -815,9 +610,13 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(thisMonthOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(thisMonthOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(thisMonthOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } case "上个月统计": { + + content = new StringBuilder(); LocalDate lastMonth = LocalDate.now().minusMonths(1); int days = LocalDate.now().getDayOfMonth(); @@ -834,12 +633,16 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(lastMonthOrders.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(lastMonthOrders.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(lastMonthOrders).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } //总统计 case "总统计": { + + content = new StringBuilder(); content.append("总统计:\n"); content.append("订单总数:").append(orderRows.size()).append("\r"); content.append("已付款:").append(orderRows.stream().filter(orderRow -> orderRow.getValidCode() == 16).count()).append("\r"); @@ -849,11 +652,15 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append("已付款佣金:").append(orderRows.stream().filter(orderRow -> orderRow.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum()).append("\r"); content.append("已完成佣金:").append(orderRows.stream().filter(orderRow -> orderRow.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum()); content.append("\r" + "违规佣金:").append(getStreamForWeiGui(orderRows).mapToDouble(orderRow -> orderRow.getEstimateCosPrice() * orderRow.getCommissionRate() * 0.01).sum()); + + contents.add(content); break; } case "今日订单": { + + content = new StringBuilder(); List todayOrders = filterOrdersByDate(orderRows, 0); // 订单总数,已付款,已取消,佣金总计 content.append("今日统计:\n"); @@ -870,9 +677,12 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { orderUtil.orderToWx(orderRow, false); } + contents.add(content); break; } case "昨日订单": { + + content = new StringBuilder(); List yesterdayOrders = filterOrdersByDate(orderRows, 1); List todayOrders = filterOrdersByDate(orderRows, 0); yesterdayOrders.removeAll(todayOrders); @@ -888,9 +698,13 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { for (OrderRow orderRow : yesterdayOrders) { orderUtil.orderToWx(orderRow, false); } + + contents.add(content); break; } case "刷新7天": { + + content = new StringBuilder(); long start = System.currentTimeMillis(); int count = 0; LocalDateTime startDate = LocalDateTime.now().minusDays(7).withMinute(0).withSecond(0).withNano(0); @@ -924,53 +738,18 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { } } content.append("刷新7天成功,耗时").append((System.currentTimeMillis() - start) / 1000).append("秒\r").append("刷新订单数:").append(count); + + contents.add(content); break; } - case "刷新3090": { - String appKey = superAdmin.getAppKey(); - String secretKey = superAdmin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - return; - } - long start = System.currentTimeMillis(); - int count = fetchHistoricalOrders3090Do(appKey, secretKey); - long time = System.currentTimeMillis() - start; - content.append("订单行:").append(count).append(",耗时: ").append(time).append("ms, ").append((time) / 1000).append(" s\r"); - break; - - } - case "刷新1430": { - String appKey = superAdmin.getAppKey(); - String secretKey = superAdmin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - return; - } - long start = System.currentTimeMillis(); - int count = fetchHistoricalOrders1430Do(appKey, secretKey); - long time = System.currentTimeMillis() - start; - content.append("订单行:").append(count).append(",耗时: ").append(time).append("ms, ").append((time) / 1000).append(" s\r"); - - break; - } - case "刷新0714": { - String appKey = superAdmin.getAppKey(); - String secretKey = superAdmin.getSecretKey(); - if (Util.isAnyEmpty(appKey, secretKey)) { - return; - } - long start = System.currentTimeMillis(); - int count = fetchHistoricalOrders0714Do(appKey, secretKey); - long time = System.currentTimeMillis() - start; - content.append("订单行:").append(count).append(",耗时: ").append(time).append("ms, ").append((time) / 1000).append(" s\r"); - break; - } - default: sendOrderToWxByOrderJDAdvanced(order, fromWxid); } - if (content.length() > 0) { - wxUtil.sendTextMessage(fromWxid, content.toString(), 1, fromWxid); + if (!contents.isEmpty()) { + for (StringBuilder stringBuilder : contents) { + wxUtil.sendTextMessage(fromWxid, stringBuilder.toString(), 1, fromWxid); + } } } @@ -985,9 +764,10 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { String unionId = superAdmin.getUnionId(); List orderRows = orderRowRepository.findByValidCodeNotInOrderByOrderTimeDescAndUnionId(param, Long.valueOf(unionId)); - + List contents = new ArrayList<>(); StringBuilder content = new StringBuilder(); if (order.startsWith("高级")) { + content = new StringBuilder(); order = order.replace("高级", ""); if (order.startsWith("违规")) { String days = order.replace("违规", ""); @@ -1001,8 +781,12 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { content.append(daysInt).append("天").append("\r\n"); - Map skuIdViolationCountMap = filterOrdersByDays.stream().filter(orderRow -> orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28).filter(orderRow -> orderRow.getSkuName() != null).collect(Collectors.groupingBy(OrderRow::getSkuName, Collectors.counting())); - + Map skuIdViolationCountMap = filterOrdersByDays.stream() + .filter(orderRow -> orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28).filter(orderRow -> orderRow.getSkuName() != null) + .collect(Collectors.groupingBy( + OrderRow::getSkuName, // ✅ 拼接SKU + Collectors.counting() + )); Map> orderInfoMap = filterOrdersByDays.stream().filter(orderRow -> orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28).filter(orderRow -> orderRow.getSkuName() != null).map(orderRow -> { OrderInfo info = new OrderInfo(); info.setSkuName(orderRow.getSkuName()); @@ -1018,7 +802,9 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { num++; String skuName = entry.getKey(); Long count = entry.getValue(); - content.append("\n").append(num).append(",商品:").append(skuName).append("\r\r").append(" 违规次数:").append(count).append("\r"); +// 修改后直接使用已包含SKU信息的key + content.append("\n").append(num).append(",商品:").append(entry.getKey()) // 这里已包含SKU信息 + .append("\r\r").append(" 违规次数:").append(count).append("\r"); List infos = orderInfoMap.get(skuName); if (infos != null) { for (OrderInfo info : infos) { @@ -1026,18 +812,56 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { } } } + contents.add(content); } - // 订单状态查询 - if (order.startsWith("3") || order.startsWith("2")) { + // 订单查询 + if (order.startsWith("搜索")) { + order = order.replace("搜索", ""); + + content = new StringBuilder(); + // 精准查询订单号+精准查询sku+模糊查询收件人+模糊查询地址 + content.append("精准查询订单号:\r"); List orderRowList = orderRowRepository.findByOrderId(Long.parseLong(order)); if (!orderRowList.isEmpty()) { OrderRow orderRow = orderRowList.get(0); - content.append(orderUtil.getFormattedOrderInfo(orderRow, orderRow.getValidCode())); + if (orderRow.getUnionId().equals(Long.parseLong(unionId))) { + content.append(orderUtil.getFormattedOrderInfo(orderRow, orderRow.getValidCode())); + } else { + content.append("订单不属于你,无法查询\r"); + } } else { - content.append("订单不存在"); + content.append("订单不存在\r"); } + contents.add(content); + + content = new StringBuilder(); + // 不统计已取消的订单 + content.append("精准查询sku,不统计已取消的订单:\r"); + int[] validCodes = {-1, 3}; + + List bySkuIdAndUnionId = orderRowRepository.findBySkuIdAndUnionId(validCodes, Long.parseLong(order), Long.parseLong(unionId)); + int size = bySkuIdAndUnionId.size(); + content.append("查询到").append(size).append("条订单\r"); + // 切割成20条20条返回前100条 + for (int i = 0; i < size; i += 20) { + List subList = bySkuIdAndUnionId.subList(i, Math.min(i + 20, size)); + content.append("第").append(i / 20 + 1).append("页:\r"); + for (OrderRow orderRow : subList) { + content.append(orderUtil.getFormattedOrderInfo(orderRow, orderRow.getValidCode())); + contents.add(content); + content = new StringBuilder(); + } + } + content = new StringBuilder(); + content.append("模糊查询收件人+模糊查询地址:\r"); + //List orderRowList = orderRowRepository + content.append("暂不支持"); + contents.add(content); + + } if (order.startsWith("SKU")) { + content = new StringBuilder(); order = order.replace("SKU", ""); String[] split = order.split("\r\n"); content.append("电脑端").append("\r\n"); @@ -1052,16 +876,18 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { } wxUtil.sendTextMessage(fromWxid, content.toString(), 1, fromWxid); content = new StringBuilder(); - + contents.add(content); } // 转链 if (order.startsWith("转链")) { + content = new StringBuilder(); order = order.replace("转链", ""); String[] split = order.split("\r\n"); for (String s : split) { content.append("https://item.jd.com/").append(s.trim()).append(".html").append("\r\n"); } + contents.add(content); } } else { try { @@ -1070,27 +896,12 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { throw new RuntimeException(e); } } - if (content.length() > 0) { - wxUtil.sendTextMessage(fromWxid, content.toString(), 1, fromWxid); + if (!contents.isEmpty()) { + for (StringBuilder stringBuilder : contents) { + wxUtil.sendTextMessage(fromWxid, stringBuilder.toString(), 1, fromWxid); + } } } - //public UnionOpenGoodsBigfieldQueryResponse getUnionOpenGoodsBigfieldQueryResponse(){ - // JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, APP_KEY, SECRET_KEY); - // - // UnionOpenGoodsBigfieldQueryRequest request=new UnionOpenGoodsBigfieldQueryRequest(); - // BigFieldGoodsReq goodsReq=new BigFieldGoodsReq(); - // goodsReq.setSkuIds(); - // request.setGoodsReq(goodsReq); - // request.setVersion("1.0"); - // UnionOpenGoodsBigfieldQueryResponse response= null; - // try { - // response = client.execute(request); - // } catch (Exception e) { - // throw new RuntimeException(e); - // } - // return response; - //} - /** * 获取订单列表 @@ -1170,6 +981,156 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { return result; } + //public UnionOpenGoodsBigfieldQueryResponse getUnionOpenGoodsBigfieldQueryResponse(){ + // JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, APP_KEY, SECRET_KEY); + // + // UnionOpenGoodsBigfieldQueryRequest request=new UnionOpenGoodsBigfieldQueryRequest(); + // BigFieldGoodsReq goodsReq=new BigFieldGoodsReq(); + // goodsReq.setSkuIds(); + // request.setGoodsReq(goodsReq); + // request.setVersion("1.0"); + // UnionOpenGoodsBigfieldQueryResponse response= null; + // try { + // response = client.execute(request); + // } catch (Exception e) { + // throw new RuntimeException(e); + // } + // return response; + //} + + /** + * 消毒柜部分的业务逻辑 + */ + @Scheduled(fixedRate = 60000) // 每分钟执行一次 + public void cleanUpTimeoutStates() { + LocalDateTime now = LocalDateTime.now(); + redisTemplate.keys(INTERACTION_STATE_PREFIX + "*").forEach(key -> { + String stateJson = redisTemplate.opsForValue().get(key); + try { + UserInteractionState state = objectMapper.readValue(stateJson, UserInteractionState.class); + LocalDateTime lastInteractionTime = LocalDateTime.parse(state.getLastInteractionTime(), DATE_TIME_FORMATTER); + if (ChronoUnit.MINUTES.between(lastInteractionTime, now) > TIMEOUT_MINUTES) { + redisTemplate.delete(key); + logger.debug("Deleted timeout state for key: {}", key); + } + } catch (Exception e) { + logger.error("Error parsing interaction state: {}", e.getMessage()); + } + }); + } + + public void handleUserInteraction(String fromWxid, String message) { + String key = INTERACTION_STATE_PREFIX + fromWxid; + String stateJson = redisTemplate.opsForValue().get(key); + UserInteractionState state; + if (stateJson == null) { + state = new UserInteractionState(); + logger.debug("New interaction state created for user: {}", fromWxid); + } else { + try { + state = objectMapper.readValue(stateJson, UserInteractionState.class); + // 检查是否超时 + LocalDateTime now = LocalDateTime.now(); + LocalDateTime lastInteractionTime = LocalDateTime.parse(state.getLastInteractionTime(), DATE_TIME_FORMATTER); + if (ChronoUnit.MINUTES.between(lastInteractionTime, now) > TIMEOUT_MINUTES) { + redisTemplate.delete(key); + logger.debug("Deleted timeout state for user: {}", fromWxid); + state = new UserInteractionState(); + } + } catch (Exception e) { + logger.error("Error parsing interaction state: {}", e.getMessage()); + state = new UserInteractionState(); + } + } + state.updateLastInteractionTime(); + + switch (state.getCurrentState()) { + case "INIT": + if ("登记".equals(message)) { + // 开始登记新的订单 + state.setCurrentState("DISINFECTANT_CABINET"); + state.setCurrentField("orderId"); + wxUtil.sendTextMessage(fromWxid, "请输入订单号:", 1, fromWxid); + logger.debug("User {} entered DISINFECTANT_CABINET state", fromWxid); + } + break; + case "DISINFECTANT_CABINET": + if ("退出".equals(message)) { + state.setCurrentState("INIT"); + wxUtil.sendTextMessage(fromWxid, "退出登记", 1, fromWxid); + logger.debug("User {} exited DISINFECTANT_CABINET state", fromWxid); + } else { + state.getCollectedFields().put(state.getCurrentField(), message); + if (state.getCurrentField().equals("orderId")) { + state.setCurrentField("recipientName"); + wxUtil.sendTextMessage(fromWxid, "请输入收件人姓名:", 1, fromWxid); + } else if (state.getCurrentField().equals("recipientName")) { + state.setCurrentField("recipientPhone"); + wxUtil.sendTextMessage(fromWxid, "请输入收件人电话:", 1, fromWxid); + } else if (state.getCurrentField().equals("recipientPhone")) { + // 所有字段收集完毕,保存订单 + saveProductOrder(state.getCollectedFields()); + state.setCurrentState("INIT"); + wxUtil.sendTextMessage(fromWxid, "订单已登记", 1, fromWxid); + logger.debug("User {} completed order registration", fromWxid); + } + } + break; + default: + wxUtil.sendTextMessage(fromWxid, "无效的状态,请重新开始对话", 1, fromWxid); + state.setCurrentState("INIT"); + logger.debug("User {} reset to INIT state due to invalid state", fromWxid); + break; + } + + try { + redisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(state), TIMEOUT_MINUTES, TimeUnit.MINUTES); + logger.debug("Saved interaction state for user {}: {}", fromWxid, state); + } catch (Exception e) { + logger.error("Error saving interaction state: {}", e.getMessage()); + } + } + + private void saveProductOrder(Map fields) { + // 创建 ProductOrder 对象并保存到数据库 + ProductOrder productOrder = new ProductOrder(); + productOrder.setOrderId(fields.get("orderId")); + productOrder.setOrderTime(new Date()); + productOrder.setRecipientName(fields.get("recipientName")); + // 设置其他字段... + + // 保存到数据库 + productOrderRepository.save(productOrder); + logger.debug("Saved product order: {}", productOrder); + } + + // 定义一个内部类来存储用户交互状态 + @Getter + @Setter + private static class UserInteractionState { + private String lastInteractionTime; + private String currentState; + private Map collectedFields; // 用于存储收集到的字段值 + private String currentField; // 当前正在询问的字段 + + public UserInteractionState() { + this.lastInteractionTime = LocalDateTime.now().format(DATE_TIME_FORMATTER); + this.currentState = "INIT"; + this.collectedFields = new HashMap<>(); + this.currentField = null; + } + + public void updateLastInteractionTime() { + this.lastInteractionTime = LocalDateTime.now().format(DATE_TIME_FORMATTER); + } + } + + // 限流异常类(需自定义) + public static class RateLimitExceededException extends RuntimeException { + public RateLimitExceededException(String message) { + super(message); + } + } @Setter @Getter @@ -1178,117 +1139,8 @@ public void sendOrderToWxByOrderDefault(String order, String fromWxid) { private Long count; private Long orderId; private Date orderDate; + } - /** - * - * 消毒柜部分的业务逻辑 - * - * - * */ -@Scheduled(fixedRate = 60000) // 每分钟执行一次 -public void cleanUpTimeoutStates() { - LocalDateTime now = LocalDateTime.now(); - redisTemplate.keys(INTERACTION_STATE_PREFIX + "*").forEach(key -> { - String stateJson = redisTemplate.opsForValue().get(key); - try { - UserInteractionState state = objectMapper.readValue(stateJson, UserInteractionState.class); - LocalDateTime lastInteractionTime = LocalDateTime.parse(state.getLastInteractionTime(), DATE_TIME_FORMATTER); - if (ChronoUnit.MINUTES.between(lastInteractionTime, now) > TIMEOUT_MINUTES) { - redisTemplate.delete(key); - logger.debug("Deleted timeout state for key: {}", key); - } - } catch (Exception e) { - logger.error("Error parsing interaction state: {}", e.getMessage()); - } - }); -} - - -public void handleUserInteraction(String fromWxid, String message) { - String key = INTERACTION_STATE_PREFIX + fromWxid; - String stateJson = redisTemplate.opsForValue().get(key); - UserInteractionState state; - if (stateJson == null) { - state = new UserInteractionState(); - logger.debug("New interaction state created for user: {}", fromWxid); - } else { - try { - state = objectMapper.readValue(stateJson, UserInteractionState.class); - // 检查是否超时 - LocalDateTime now = LocalDateTime.now(); - LocalDateTime lastInteractionTime = LocalDateTime.parse(state.getLastInteractionTime(), DATE_TIME_FORMATTER); - if (ChronoUnit.MINUTES.between(lastInteractionTime, now) > TIMEOUT_MINUTES) { - redisTemplate.delete(key); - logger.debug("Deleted timeout state for user: {}", fromWxid); - state = new UserInteractionState(); - } - } catch (Exception e) { - logger.error("Error parsing interaction state: {}", e.getMessage()); - state = new UserInteractionState(); - } - } - state.updateLastInteractionTime(); - - switch (state.getCurrentState()) { - case "INIT": - if ("登记".equals(message)) { - // 开始登记新的订单 - state.setCurrentState("DISINFECTANT_CABINET"); - state.setCurrentField("orderId"); - wxUtil.sendTextMessage(fromWxid, "请输入订单号:", 1, fromWxid); - logger.debug("User {} entered DISINFECTANT_CABINET state", fromWxid); - } - break; - case "DISINFECTANT_CABINET": - if ("退出".equals(message)) { - state.setCurrentState("INIT"); - wxUtil.sendTextMessage(fromWxid, "退出登记", 1, fromWxid); - logger.debug("User {} exited DISINFECTANT_CABINET state", fromWxid); - } else { - state.getCollectedFields().put(state.getCurrentField(), message); - if (state.getCurrentField().equals("orderId")) { - state.setCurrentField("recipientName"); - wxUtil.sendTextMessage(fromWxid, "请输入收件人姓名:", 1, fromWxid); - } else if (state.getCurrentField().equals("recipientName")) { - state.setCurrentField("recipientPhone"); - wxUtil.sendTextMessage(fromWxid, "请输入收件人电话:", 1, fromWxid); - } else if (state.getCurrentField().equals("recipientPhone")) { - // 所有字段收集完毕,保存订单 - saveProductOrder(state.getCollectedFields()); - state.setCurrentState("INIT"); - wxUtil.sendTextMessage(fromWxid, "订单已登记", 1, fromWxid); - logger.debug("User {} completed order registration", fromWxid); - } - } - break; - default: - wxUtil.sendTextMessage(fromWxid, "无效的状态,请重新开始对话", 1, fromWxid); - state.setCurrentState("INIT"); - logger.debug("User {} reset to INIT state due to invalid state", fromWxid); - break; - } - - try { - redisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(state), TIMEOUT_MINUTES, TimeUnit.MINUTES); - logger.debug("Saved interaction state for user {}: {}", fromWxid, state); - } catch (Exception e) { - logger.error("Error saving interaction state: {}", e.getMessage()); - } -} -private void saveProductOrder(Map fields) { - // 创建 ProductOrder 对象并保存到数据库 - ProductOrder productOrder = new ProductOrder(); - productOrder.setOrderId(fields.get("orderId")); - productOrder.setOrderTime(new Date()); - productOrder.setRecipientName(fields.get("recipientName")); - // 设置其他字段... - - // 保存到数据库 - productOrderRepository.save(productOrder); - logger.debug("Saved product order: {}", productOrder); -} - - } diff --git a/src/main/java/cn/van/business/util/OrderUtil.java b/src/main/java/cn/van/business/util/OrderUtil.java index c2bc47f..19c52b3 100644 --- a/src/main/java/cn/van/business/util/OrderUtil.java +++ b/src/main/java/cn/van/business/util/OrderUtil.java @@ -74,7 +74,7 @@ public class OrderUtil { "状态:" + (converter.getCodeDescription(orderRow.getValidCode())) + "\r" - + "名称:" + orderRow.getSkuName() + "\r\n" + + "名称:" + orderRow.getSkuName().substring(0, 64) + "\r\n" //+ "商品单价:" + orderRow.getPrice() + "\r" //+ "商品数量:" + orderRow.getSkuNum() + "\r" //+ "商品总价:" + (orderRow.getPrice() * orderRow.getSkuNum()) + "\r" diff --git a/src/main/java/cn/van/business/util/WXUtil.java b/src/main/java/cn/van/business/util/WXUtil.java index 04b962f..1884865 100644 --- a/src/main/java/cn/van/business/util/WXUtil.java +++ b/src/main/java/cn/van/business/util/WXUtil.java @@ -56,10 +56,8 @@ public class WXUtil { SuperAdmin admin2 = new SuperAdmin("wxid_yneqf1implxu12", "源", "2025353364", "e3c161242c8a1416fada5b5564d7ee70", "41ae9aabf03b41e6ba309682e36b323e"); super_admins.put(admin2.getWxid(), admin2); jdidToWxidMap.put(admin2.getUnionId(), admin2.getWxid()); - wxTsUtil.sendNotify("initSuperAdmins 初始化完成"); + //wxTsUtil.sendNotify("initSuperAdmins 初始化完成"); - - // add more admins as needed... } public static String getWxidFromJdid(String jdid) { diff --git a/src/main/java/cn/van/business/util/jdReq/Days0007Strategy.java b/src/main/java/cn/van/business/util/jdReq/Days0007Strategy.java new file mode 100644 index 0000000..1595f9d --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/Days0007Strategy.java @@ -0,0 +1,26 @@ +package cn.van.business.util.jdReq; + +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +@Component +public class Days0007Strategy implements OrderFetchStrategy { + @Override + public TimeRange calculateRange(LocalDateTime baseTime) { + + LocalDateTime end = baseTime.truncatedTo(ChronoUnit.HOURS); + LocalDateTime start = end.minusDays(7).truncatedTo(ChronoUnit.HOURS); + if (start.isAfter(end)) { // 防御性校验 + throw new IllegalArgumentException("时间范围错误"); + } + return new TimeRange(start, end); + } + + + @Override + public String strategyName() { + return "00-07天历史订单抓取策略"; + } +} diff --git a/src/main/java/cn/van/business/util/jdReq/Days0714Strategy.java b/src/main/java/cn/van/business/util/jdReq/Days0714Strategy.java new file mode 100644 index 0000000..d431051 --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/Days0714Strategy.java @@ -0,0 +1,25 @@ +package cn.van.business.util.jdReq; + +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +@Component +public class Days0714Strategy implements OrderFetchStrategy { + @Override + public TimeRange calculateRange(LocalDateTime baseTime) { + LocalDateTime end = baseTime.truncatedTo(ChronoUnit.HOURS).minusDays(7); + LocalDateTime start = end.minusDays(14).truncatedTo(ChronoUnit.HOURS); + if (start.isAfter(end)) { // 防御性校验 + throw new IllegalArgumentException("时间范围错误"); + } + return new TimeRange(start, end); + } + + + @Override + public String strategyName() { + return "07-14天历史订单抓取策略"; + } +} diff --git a/src/main/java/cn/van/business/util/jdReq/Days1430Strategy.java b/src/main/java/cn/van/business/util/jdReq/Days1430Strategy.java new file mode 100644 index 0000000..c93ee9c --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/Days1430Strategy.java @@ -0,0 +1,24 @@ +package cn.van.business.util.jdReq; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +// 在jdReq包中补充策略类 +public class Days1430Strategy implements OrderFetchStrategy { + @Override + public TimeRange calculateRange(LocalDateTime baseTime) { + LocalDateTime end = baseTime.minusDays(30).truncatedTo(ChronoUnit.HOURS); + LocalDateTime start = baseTime.minusDays(14).truncatedTo(ChronoUnit.HOURS); + if (start.isAfter(end)) { // 防御性校验 + throw new IllegalArgumentException("时间范围错误"); + } + return new TimeRange(start, end); + } + + @Override + public String strategyName() { + return "14-30天历史订单抓取策略"; + } +} + +// 其他策略类类似实现 diff --git a/src/main/java/cn/van/business/util/jdReq/Days3090Strategy.java b/src/main/java/cn/van/business/util/jdReq/Days3090Strategy.java new file mode 100644 index 0000000..52b4a43 --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/Days3090Strategy.java @@ -0,0 +1,24 @@ +package cn.van.business.util.jdReq; + +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +@Component +public class Days3090Strategy implements OrderFetchStrategy { + @Override + public TimeRange calculateRange(LocalDateTime baseTime) { + LocalDateTime end = baseTime.minusMonths(1); + LocalDateTime start = end.minusMonths(2); + if (start.isAfter(end)) { // 防御性校验 + throw new IllegalArgumentException("时间范围错误"); + } + return new TimeRange(start, end); + } + + + @Override + public String strategyName() { + return "30-90天历史订单抓取策略"; + } +} diff --git a/src/main/java/cn/van/business/util/jdReq/HistoricalOrderFetcher.java b/src/main/java/cn/van/business/util/jdReq/HistoricalOrderFetcher.java new file mode 100644 index 0000000..66d1ead --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/HistoricalOrderFetcher.java @@ -0,0 +1,40 @@ +//package cn.van.business.util.jdReq; +// +//import cn.van.business.repository.OrderRowRepository; +//import com.jd.open.api.sdk.response.kplunion.UnionOpenOrderRowQueryResponse; +//import org.springframework.beans.factory.annotation.Autowired; +// +//import java.time.LocalDateTime; +// +//public abstract class HistoricalOrderFetcher { +// @Autowired +// protected OrderRowRepository orderRowRepository; +// +// protected int fetchOrders(OrderFetchStrategy strategy) { +// int count = 0; +// LocalDateTime start = strategy.getStartTime(); +// LocalDateTime end = strategy.getEndTime(); +// +// while (!start.isEqual(end)) { +// Integer pageIndex = 1; +// boolean hasMore; +// +// do { +// UnionOpenOrderRowQueryResponse response = fetchPage(strategy, start, pageIndex); +// hasMore = processResponse(response, strategy); +// pageIndex++; +// } while (hasMore); +// +// start = start.plusHours(1); +// } +// return count; +// } +// +// protected abstract UnionOpenOrderRowQueryResponse fetchPage(OrderFetchStrategy strategy, +// LocalDateTime startTime, +// Integer pageIndex); +// +// private boolean processResponse(UnionOpenOrderRowQueryResponse response, OrderFetchStrategy strategy) { +// // 统一响应处理逻辑... +// } +//} diff --git a/src/main/java/cn/van/business/util/jdReq/OrderFetchStrategy.java b/src/main/java/cn/van/business/util/jdReq/OrderFetchStrategy.java new file mode 100644 index 0000000..3746600 --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/OrderFetchStrategy.java @@ -0,0 +1,18 @@ +package cn.van.business.util.jdReq; + +import java.time.LocalDateTime; + +public interface OrderFetchStrategy { + /** + * 计算要抓取的时间范围 + * @param baseTime 基准时间(通常用当前时间) + * @return 包含开始时间和结束时间的值对象 + */ + TimeRange calculateRange(LocalDateTime baseTime); + + /** + * 策略标识 + */ + String strategyName(); +} + diff --git a/src/main/java/cn/van/business/util/jdReq/StrategyFactory.java b/src/main/java/cn/van/business/util/jdReq/StrategyFactory.java new file mode 100644 index 0000000..b321ec0 --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/StrategyFactory.java @@ -0,0 +1,11 @@ +package cn.van.business.util.jdReq; + + public class StrategyFactory { + public static OrderFetchStrategy getStrategy(String type) { + switch (type) { + case "30-90": return new Days3090Strategy(); + //case "14-30": return new Days1430Strategy(); + default: throw new IllegalArgumentException(); + } + } + } diff --git a/src/main/java/cn/van/business/util/jdReq/TimeRange.java b/src/main/java/cn/van/business/util/jdReq/TimeRange.java new file mode 100644 index 0000000..939ab0a --- /dev/null +++ b/src/main/java/cn/van/business/util/jdReq/TimeRange.java @@ -0,0 +1,14 @@ +package cn.van.business.util.jdReq; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.time.LocalDateTime; + +// 时间范围值对象 +@Getter +@AllArgsConstructor +public class TimeRange { + private LocalDateTime start; + private LocalDateTime end; +}