Files
Jarvis_java/src/main/java/cn/van/business/util/JDUtil.java
2025-03-16 00:46:06 +08:00

1314 lines
58 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cn.van.business.util;
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;
import com.jd.open.api.sdk.JdClient;
import com.jd.open.api.sdk.domain.kplunion.OrderService.request.query.OrderRowReq;
import com.jd.open.api.sdk.domain.kplunion.OrderService.response.query.OrderRowResp;
import com.jd.open.api.sdk.domain.kplunion.promotionbysubunioni.PromotionService.request.get.PromotionCodeReq;
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 lombok.AllArgsConstructor;
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.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static cn.van.business.util.JDUtil.UserInteractionState.GiftMoneyStep.*;
import static cn.van.business.util.JDUtil.UserInteractionState.ProcessState.*;
import static cn.van.business.util.JDUtil.UserInteractionState.ProductOrderStep.*;
import static cn.van.business.util.WXUtil.super_admins;
/**
* @author Leo
* @version 1.0
* @create 2024/11/5 17:40
* @description
*/
@Component
public class JDUtil {
/**
* 密钥配置
*/
// van论坛
private static final String LPF_APP_KEY_WZ = "98e21c89ae5610240ec3f5f575f86a59";
private static final String LPF_SECRET_KEY_WZ = "3dcb6b23a1104639ac433fd07adb6dfb";
// 导购的
private static final String LPF_APP_KEY_DG = "faf410cb9587dc80dc7b31e321d7d322";
private static final String LPF_SECRET_KEY_DG = "a4fb15d7bedd4316b97b4e96e4effc1c";
private static final String LL_APP_KEY_DG = "9c2011409f0fc906b73432dd3687599d";
private static final String LL_SECRET_KEY_DG = "3ceddff403e544a8a2eacc727cf05dab";
/**
* 实际业务处理
*/
// 标记是否拉取过小时的订单空订单会set 一个 tag避免重复拉取
private static final String JD_REFRESH_TAG = "jd:refresh:tag:";
private static final String SERVER_URL = "https://api.jd.com/routerjson";
//accessToken
private static final String ACCESS_TOKEN = "";
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;
// 添加ObjectMapper来序列化和反序列化UserInteractionState
private final ObjectMapper objectMapper = new ObjectMapper();
// Getter 方法,方便外部访问
@Getter
@Value("${isRunning.wx}")
private String isRunning_wx;
@Getter
@Value("${isRunning.jd}")
private String isRunning_jd;
// 构造函数中注入StringRedisTemplate
@Autowired
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;
}
private static List<OrderRow> filterOrdersByDate(List<OrderRow> orderRows, int daysBack) {
LocalDate now = LocalDate.now();
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());
}
private static Stream<OrderRow> getStreamForWeiGui(List<OrderRow> todayOrders) {
return todayOrders.stream().filter(orderRow -> orderRow.getValidCode() == 13 || orderRow.getValidCode() == 25 || orderRow.getValidCode() == 26 || orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28 || orderRow.getValidCode() == 29);
}
/**
* 将 响应参数转化为 OrderRow并返回
*/
private OrderRow createOrderRow(OrderRowResp orderRowResp) {
OrderRow orderRow = new OrderRow();
orderRow.setOrderId(orderRowResp.getOrderId());
orderRow.setSkuId(orderRowResp.getSkuId());
orderRow.setSkuName(orderRowResp.getSkuName());
orderRow.setItemId(orderRowResp.getItemId());
orderRow.setSkuNum(orderRowResp.getSkuNum());
orderRow.setPrice(orderRowResp.getPrice());
orderRow.setActualCosPrice(orderRowResp.getActualCosPrice());
orderRow.setActualFee(orderRowResp.getActualFee());
orderRow.setEstimateCosPrice(orderRowResp.getEstimateCosPrice());
orderRow.setEstimateFee(orderRowResp.getEstimateFee());
orderRow.setSubSideRate(orderRowResp.getSubSideRate());
orderRow.setSubsidyRate(orderRowResp.getSubsidyRate());
orderRow.setCommissionRate(orderRowResp.getCommissionRate());
orderRow.setFinalRate(orderRowResp.getFinalRate());
orderRow.setOrderTime(DateUtils.parseDate(orderRowResp.getOrderTime()));
orderRow.setFinishTime(DateUtils.parseDate(orderRowResp.getFinishTime()));
orderRow.setOrderTag(orderRowResp.getOrderTag());
orderRow.setOrderEmt(orderRowResp.getOrderEmt());
orderRow.setUnionId(orderRowResp.getUnionId());
orderRow.setUnionRole(orderRowResp.getUnionRole());
orderRow.setUnionAlias(orderRowResp.getUnionAlias());
orderRow.setUnionTag(orderRowResp.getUnionTag());
orderRow.setTraceType(orderRowResp.getTraceType());
orderRow.setValidCode(orderRowResp.getValidCode());
orderRow.setPayMonth(orderRowResp.getPayMonth());
orderRow.setSiteId(orderRowResp.getSiteId());
orderRow.setParentId(orderRowResp.getParentId());
//GoodsInfo goodsInfo = orderRowResp.getGoodsInfo();
//GoodsInfoVO goodsInfoVO = new GoodsInfoVO();
//goodsInfoVO.setShopId(String.valueOf(goodsInfo.getShopId()));
//goodsInfoVO.setShopName(goodsInfo.getShopName());
//goodsInfoVO.setOwner(goodsInfo.getOwner());
//goodsInfoVO.setProductId(String.valueOf(goodsInfo.getProductId()));
//goodsInfoVO.setImageUrl(goodsInfo.getImageUrl());
//orderRow.setGoodsInfo(goodsInfoVO);
orderRow.setCallerItemId(orderRowResp.getCallerItemId());
orderRow.setPid(orderRowResp.getPid());
orderRow.setCid1(orderRowResp.getCid1());
orderRow.setCid2(orderRowResp.getCid2());
orderRow.setCid3(orderRowResp.getCid3());
orderRow.setChannelId(orderRowResp.getChannelId());
orderRow.setProPriceAmount(orderRowResp.getProPriceAmount());
orderRow.setSkuFrozenNum(orderRowResp.getSkuFrozenNum());
orderRow.setSkuReturnNum(orderRowResp.getSkuReturnNum());
orderRow.setSkuTag(orderRowResp.getSkuTag());
orderRow.setPositionId(orderRowResp.getPositionId());
orderRow.setPopId(orderRowResp.getPopId());
orderRow.setRid(orderRowResp.getRid());
orderRow.setPlus(orderRowResp.getPlus());
orderRow.setCpActId(orderRowResp.getCpActId());
orderRow.setGiftCouponKey(orderRowResp.getGiftCouponKey());
orderRow.setModifyTime(new Date());
orderRow.setSign(orderRowResp.getSign());
orderRow.setBalanceExt(orderRowResp.getBalanceExt());
orderRow.setExpressStatus(orderRowResp.getExpressStatus());
orderRow.setExt1(orderRowResp.getExt1());
orderRow.setSubUnionId(orderRowResp.getSubUnionId());
orderRow.setGiftCouponOcsAmount(orderRowResp.getGiftCouponOcsAmount());
orderRow.setTraceType(orderRowResp.getTraceType());
orderRow.setExpressStatus(orderRowResp.getExpressStatus());
orderRow.setTraceType(orderRowResp.getTraceType());
orderRow.setId(orderRowResp.getId());
orderRow.setValidCode(orderRowResp.getValidCode());
orderRow.setExpressStatus(orderRowResp.getExpressStatus());
orderRow.setTraceType(orderRowResp.getTraceType());
return orderRow;
}
public int fetchOrders(OrderFetchStrategy strategy, String appKey, String secretKey) {
TimeRange range = strategy.calculateRange(LocalDateTime.now());
int count = 0;
// 复用原有的抓取逻辑
LocalDateTime current = range.getStart();
while (!current.isAfter(range.getEnd())) {
// 调用分页抓取API...
Integer pageIndex = 1;
boolean hasMore = true;
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++;
}
current = current.plusHours(1);
}
return count;
}
/**
* 实时刷新最近10分钟的订单Resilience4j限流集成
*/
@Scheduled(cron = "0 * * * * ?")
public void fetchLatestOrder() {
if (isRunning_jd.equals("true")) {
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);
}
/**
* 扫描订单发送到微信
* 每分钟的30秒执行一次
*/
@Scheduled(cron = "3 * * * * ?")
public void sendOrderToWx() {
if (isRunning_wx.equals("true")) {
//long start = System.currentTimeMillis();
int[] validCodes = {-1};
// 只要三个月的,更多的也刷新不出来的
Date threeMonthsAgo = Date.from(LocalDateTime.now().minusMonths(3).atZone(ZoneId.systemDefault()).toInstant());
List<OrderRow> orderRows = orderRowRepository.findByValidCodeNotInAndOrderTimeGreaterThanOrderByOrderTimeDesc(validCodes, threeMonthsAgo);
for (OrderRow orderRow : orderRows) {
orderUtil.orderToWx(orderRow, true);
}
//logger.info("扫描订单发送到微信耗时:{} ms, 订单数:{} ", System.currentTimeMillis() - start, orderRows.size());
}
}
/**
* 一天拉取三次 30天到60天前的订单
*/
@Scheduled(cron = "0 0 */4 * * ?")
public void fetchHistoricalOrders3090() {
if (isRunning_jd.equals("true")) {
try {
OrderFetchStrategy strategy = new Days3090Strategy();
for (WXUtil.SuperAdmin admin : super_admins.values()) {
try {
int count = fetchOrders(strategy, admin.getAppKey(), admin.getSecretKey());
logger.info("账号{} 3090订单拉取完成新增{}条", admin.getAppKey().substring(18), count);
} catch (Exception e) {
logger.error("账号 {} 拉取异常: {}", admin.getAppKey().substring(18), e.getMessage());
}
}
} catch (Exception ex) {
logger.error("策略执行异常", ex);
}
}
}
/**
* 一天拉取6次 14天到30天前的订单
*/
@Scheduled(cron = "0 0 * * * ?")
public void fetchHistoricalOrders1430() {
if (isRunning_jd.equals("true")) {
try {
OrderFetchStrategy strategy = new Days1430Strategy(); // 需补充Days1430Strategy实现
for (WXUtil.SuperAdmin admin : super_admins.values()) {
try {
int count = fetchOrders(strategy, admin.getAppKey(), admin.getSecretKey());
logger.info("账号{} 1430订单拉取完成新增{}条", admin.getAppKey().substring(18), count);
} catch (Exception e) {
logger.error("账号 {} 拉取异常: {}", admin.getAppKey().substring(18), e.getMessage());
}
}
} catch (Exception ex) {
logger.error("1430策略执行异常", ex);
}
}
}
/**
* 每10分钟拉取07-14天的订单
*/
@Scheduled(cron = "0 0 * * * ?")
public void fetchHistoricalOrders0714() {
if (isRunning_jd.equals("true")) {
try {
OrderFetchStrategy strategy = new Days0714Strategy();
super_admins.values().parallelStream().forEach(admin -> {
if (Util.isAnyEmpty(admin.getAppKey(), admin.getSecretKey())) return;
try {
int count = fetchOrders(strategy, admin.getAppKey(), admin.getSecretKey());
logger.info("账号{} 0714订单拉取完成新增{}条", admin.getAppKey().substring(18), count);
} catch (Exception e) {
logger.error("账号 {} 0714拉取异常: {}", admin.getAppKey().substring(18), e.getMessage());
}
});
} catch (Exception ex) {
logger.error("0714策略执行异常", ex);
}
}
}
@Scheduled(cron = "0 */5 * * * ?")
public void fetchHistoricalOrders0007() {
if (isRunning_jd.equals("true")) {
try {
OrderFetchStrategy strategy = new Days0007Strategy();
super_admins.values().parallelStream().forEach(admin -> {
if (Util.isAnyEmpty(admin.getAppKey(), admin.getSecretKey())) return;
try {
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) {
logger.error("账号{}0007拉取异常: {}", admin.getAppKey().substring(18), e.getMessage());
}
});
} catch (Exception ex) {
logger.error("0007策略执行异常", ex);
}
}
}
/**
* 根据指定的日期时间拉取订单
*
* @param startTime 开始时间
* isRealTime 是否是实时订单 是的话不会判断是否拉取过
* page 分页页码
* isMinutes 是否是分钟级订单 分钟的每次加10分钟小时每小时加1小时
*/
public UnionOpenOrderRowQueryResponse fetchOrdersForDateTime(LocalDateTime startTime, boolean isRealTime, Integer page, boolean isMinutes, String appKey, String secretKey) {
LocalDateTime endTime = isMinutes ? startTime.plusMinutes(10) : startTime.plusHours(1);
String hourMinuteTag = isRealTime ? "minute" : "hour";
//String oldTimeTag = JD_REFRESH_TAG + startTime.format(DATE_TIME_FORMATTER);
String newTimeTag = JD_REFRESH_TAG + appKey + ":" + startTime.format(DATE_TIME_FORMATTER);
HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
// 检查这个小时或分钟是否已经被处理过
if (hashOps.hasKey(newTimeTag, hourMinuteTag)) {
if (!isMinutes) {
return null;
}
}
// 调用 API 以拉取订单
try {
UnionOpenOrderRowQueryResponse unionOpenOrderRowQueryResponse = getUnionOpenOrderRowQueryResponse(startTime, endTime, page, appKey, secretKey);
// 历史的订单才进行标记为已拉取,小时分钟的都进行拉取并且标记
if (!isRealTime) {
// 只有没有订单的才进行标记为已拉取
if (unionOpenOrderRowQueryResponse != null && unionOpenOrderRowQueryResponse.getQueryResult() != null && unionOpenOrderRowQueryResponse.getQueryResult().getData() == null) {
hashOps.put(newTimeTag, hourMinuteTag, "done");
}
}
// 打印方法调用和开始结束时间
if (isRealTime && (LocalDateTime.now().getMinute() % 10 == 0)) {
logger.debug(" {} --- 拉取订单, 分钟还是秒 {} , 开始时间:{} --- 结束时间:{}", appKey.substring(appKey.length() - 4), hourMinuteTag, startTime.format(DATE_TIME_FORMATTER), endTime.format(DATE_TIME_FORMATTER));
}
return unionOpenOrderRowQueryResponse;
} catch (Exception e) {
return null;
}
}
public void sendOrderToWxByOrderDefault(String order, String fromWxid) {
logger.info("执行 sendOrderToWxByOrderDefault 方法order: {}, fromWxid: {}", order, fromWxid);
handleUserInteraction(fromWxid, order);
// 具体逻辑
}
private OrderStats calculateStats(List<OrderRow> orders) {
long paid = orders.stream().filter(o -> o.getValidCode() == 16).count();
long pending = orders.stream().filter(o -> o.getValidCode() == 15).count();
long canceled = orders.stream().filter(o -> o.getValidCode() != 16 && o.getValidCode() != 17).count();
long completed = orders.stream().filter(o -> o.getValidCode() == 17).count();
return new OrderStats(orders.size(), orders.size() - canceled, paid, orders.stream().filter(o -> o.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum(), pending, orders.stream().filter(o -> o.getValidCode() == 15).mapToDouble(OrderRow::getEstimateFee).sum(), canceled, completed, orders.stream().filter(o -> o.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum(), getStreamForWeiGui(orders).count(), getStreamForWeiGui(orders).mapToDouble(o -> o.getEstimateCosPrice() * o.getCommissionRate() * 0.01).sum());
}
private StringBuilder buildStatsContent(String title, OrderStats stats) {
StringBuilder content = new StringBuilder();
content.append(title).append("\n").append("订单总数:").append(stats.getTotalOrders()).append("\r").append("订单总数(不含取消)").append(stats.getValidOrders()).append("\r\n").append("已付款:").append(stats.getPaidOrders()).append("\r").append("已付款佣金:").append(stats.getPaidCommission()).append("\r\n").append("待付款:").append(stats.getPendingOrders()).append("\r") // 修正了原代码中的Stream未终止问题
.append("待付款佣金:").append(stats.getPendingCommission()).append("\r\n").append("已取消:").append(stats.getCanceledOrders()).append("\r").append("已完成:").append(stats.getCompletedOrders()).append("\r").append("已完成佣金:").append(stats.getCompletedCommission()).append("\r").append("违规:").append(stats.getViolations()).append("\r").append("违规佣金:").append(stats.getViolationCommission());
return content;
}
/**
* 接收京粉指令指令
*/
public void sendOrderToWxByOrderJD(String order, String fromWxid) {
int[] param = {-1};
WXUtil.SuperAdmin superAdmin = super_admins.get(fromWxid);
String unionId = superAdmin.getUnionId();
List<OrderRow> orderRows = orderRowRepository.findByValidCodeNotInOrderByOrderTimeDescAndUnionId(param, Long.valueOf(unionId));
/**
* 菜单:
* 今日统计
* 昨日统计
* 最近七天统计
* 最近一个月统计
* 今天订单
* 昨天订单
* */
List<StringBuilder> contents = new ArrayList<>();
StringBuilder content = new StringBuilder();
switch (order) {
case "菜单":
content.append("菜单:京+命令 \n 如: 京今日统计\r");
content.append("今日统计\r");
content.append("昨天统计\r");
content.append("七日统计\r");
content.append("一个月统计\r");
content.append("两个月统计\r");
content.append("三个月统计\r");
content.append("总统计\r\n");
content.append("这个月统计\r");
content.append("上个月统计\r\n");
content.append("今日订单\r");
content.append("昨日订单\r");
content.append("七日订单\r");
content.append("刷新7天\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);
content = new StringBuilder();
content.append("礼金\r");
content.append("转链\r");
contents.add(content);
break;
case "测试指令": {
//test01();
break;
}
case "今日统计": {
content = new StringBuilder();
// 订单总数,已付款,已取消,佣金总计
List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
OrderStats stats = calculateStats(todayOrders);
contents.add(buildStatsContent("今日统计", stats));
contents.add(content);
break;
}
case "昨日统计": {
content = new StringBuilder();
List<OrderRow> yesterdayOrders = filterOrdersByDate(orderRows, 1);
OrderStats stats = calculateStats(yesterdayOrders);
contents.add(buildStatsContent("昨日统计", stats));
contents.add(content);
break;
}
case "三日统计": {
content = new StringBuilder();
List<OrderRow> last3DaysOrders = filterOrdersByDate(orderRows, 3);
OrderStats stats = calculateStats(last3DaysOrders);
contents.add(buildStatsContent("三日统计", stats));
contents.add(content);
break;
}
case "七日统计": {
content = new StringBuilder();
List<OrderRow> last7DaysOrders = filterOrdersByDate(orderRows, 7);
OrderStats stats = calculateStats(last7DaysOrders);
contents.add(buildStatsContent("七日统计", stats));
contents.add(content);
break;
}
case "一个月统计": {
content = new StringBuilder();
List<OrderRow> last30DaysOrders = filterOrdersByDate(orderRows, 30);
OrderStats stats = calculateStats(last30DaysOrders);
contents.add(buildStatsContent("一个月统计", stats));
contents.add(content);
break;
}
case "两个月统计": {
content = new StringBuilder();
List<OrderRow> last60DaysOrders = filterOrdersByDate(orderRows, 60);
OrderStats stats = calculateStats(last60DaysOrders);
contents.add(buildStatsContent("两个月统计", stats));
contents.add(content);
break;
}
case "三个月统计": {
content = new StringBuilder();
List<OrderRow> last90DaysOrders = filterOrdersByDate(orderRows, 90);
OrderStats stats = calculateStats(last90DaysOrders);
contents.add(buildStatsContent("三个月统计", stats));
contents.add(content);
break;
}
case "这个月统计": {
content = new StringBuilder();
// 计算出距离1号有几天
int days = LocalDate.now().getDayOfMonth();
List<OrderRow> thisMonthOrders = filterOrdersByDate(orderRows, days);
OrderStats stats = calculateStats(thisMonthOrders);
contents.add(buildStatsContent("这个月统计", stats));
contents.add(content);
break;
}
case "上个月统计": {
content = new StringBuilder();
LocalDate lastMonth = LocalDate.now().minusMonths(1);
int days = LocalDate.now().getDayOfMonth();
List<OrderRow> lastMonthOrders = filterOrdersByDate(orderRows, lastMonth.lengthOfMonth() + days);
List<OrderRow> thisMonthOrders = filterOrdersByDate(orderRows, days);
lastMonthOrders = lastMonthOrders.stream().filter(orderRow -> !thisMonthOrders.contains(orderRow)).collect(Collectors.toList());
OrderStats stats = calculateStats(lastMonthOrders);
contents.add(buildStatsContent("上个月统计", stats));
contents.add(content);
break;
}
//总统计
case "总统计": {
content = new StringBuilder();
OrderStats stats = calculateStats(orderRows);
contents.add(buildStatsContent("总统计", stats));
contents.add(content);
break;
}
case "今日订单": {
content = new StringBuilder();
List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
// 订单总数,已付款,已取消,佣金总计
OrderStats stats = calculateStats(todayOrders);
contents.add(buildStatsContent("今日统计", stats));
if (!todayOrders.isEmpty()) {
orderUtil.orderToWxBatch(todayOrders);
}
contents.add(content);
break;
}
case "昨日订单": {
content = new StringBuilder();
List<OrderRow> yesterdayOrders = filterOrdersByDate(orderRows, 1);
List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
yesterdayOrders.removeAll(todayOrders);
OrderStats stats = calculateStats(yesterdayOrders);
contents.add(buildStatsContent("昨日统计", stats));
if (!yesterdayOrders.isEmpty()) {
orderUtil.orderToWxBatch(yesterdayOrders);
}
contents.add(content);
break;
}
case "七日订单": {
content = new StringBuilder();
List<OrderRow> last7DaysOrders = filterOrdersByDate(orderRows, 1);
List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
last7DaysOrders.removeAll(todayOrders);
OrderStats stats = calculateStats(last7DaysOrders);
contents.add(buildStatsContent("七日统计", stats));
if (!last7DaysOrders.isEmpty()) {
orderUtil.orderToWxBatch(last7DaysOrders);
}
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);
LocalDateTime lastHour = LocalDateTime.now().minusHours(1).withMinute(0).withSecond(0).withNano(0);
String appKey = superAdmin.getAppKey();
String secretKey = superAdmin.getSecretKey();
if (Util.isAnyEmpty(appKey, secretKey)) {
return;
}
while (!startDate.isEqual(lastHour)) {
startDate = startDate.plusHours(1);
UnionOpenOrderRowQueryResponse response = fetchOrdersForDateTime(startDate, false, 1, false, appKey, secretKey);
if (response != null) {
int code = response.getQueryResult().getCode();
if (code == 200) {
if (response.getQueryResult().getCode() == 200) {
OrderRowResp[] orderRowResps = response.getQueryResult().getData();
if (orderRowResps == null) {
continue;
}
for (OrderRowResp orderRowResp : orderRowResps) {
// 固化到数据库
OrderRow orderRow = createOrderRow(orderRowResp);
// 订单号不存在就保存,存在就更新订单状态
orderRowRepository.save(orderRow);
count++;
}
}
}
}
}
content.append("刷新7天成功,耗时").append((System.currentTimeMillis() - start) / 1000).append("\r").append("刷新订单数:").append(count);
contents.add(content);
break;
}
default:
sendOrderToWxByOrderJDAdvanced(order, fromWxid);
}
if (!contents.isEmpty()) {
for (StringBuilder stringBuilder : contents) {
wxUtil.sendTextMessage(fromWxid, stringBuilder.toString(), 1, fromWxid);
}
}
}
/**
* 接收京粉指令指令
* 高级菜单
*/
public void sendOrderToWxByOrderJDAdvanced(String order, String fromWxid) {
int[] param = {-1};
WXUtil.SuperAdmin superAdmin = super_admins.get(fromWxid);
String unionId = superAdmin.getUnionId();
List<OrderRow> orderRows = orderRowRepository.findByValidCodeNotInOrderByOrderTimeDescAndUnionId(param, Long.valueOf(unionId));
List<StringBuilder> contents = new ArrayList<>();
StringBuilder content = new StringBuilder();
if (order.startsWith("高级")) {
content = new StringBuilder();
order = order.replace("高级", "");
if (order.startsWith("违规")) {
String days = order.replace("违规", "");
Integer daysInt = 365;
if (Util.isNotEmpty(days)) {
daysInt = Integer.parseInt(days);
}
List<OrderRow> filterOrdersByDays = filterOrdersByDate(orderRows, daysInt);
content.append("违规排行:");
content.append(daysInt).append("").append("\r\n");
Map<String, Long> 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<String, List<OrderInfo>> 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());
info.setOrderId(orderRow.getOrderId());
info.setOrderDate(orderRow.getOrderTime());
return info;
}).collect(Collectors.groupingBy(OrderInfo::getSkuName));
List<Map.Entry<String, Long>> sortedViolationCounts = skuIdViolationCountMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList());
Integer num = 0;
for (Map.Entry<String, Long> entry : sortedViolationCounts) {
num++;
String skuName = entry.getKey();
Long count = entry.getValue();
// 修改后直接使用已包含SKU信息的key
content.append("\n").append(num).append(",商品:").append(entry.getKey()) // 这里已包含SKU信息
.append("\r\r").append(" 违规次数:").append(count).append("\r");
List<OrderInfo> infos = orderInfoMap.get(skuName);
if (infos != null) {
for (OrderInfo info : infos) {
content.append("\n 订单:").append(info.getOrderId()).append("\r 下单:").append(info.getOrderDate()).append("\r");
}
}
}
contents.add(content);
}
// 订单查询
if (order.startsWith("搜索")) {
order = order.replace("搜索", "");
content = new StringBuilder();
// 精准查询订单号+精准查询sku+模糊查询收件人+模糊查询地址
content.append("精准查询订单号:\r");
List<OrderRow> orderRowList = orderRowRepository.findByOrderId(Long.parseLong(order));
if (!orderRowList.isEmpty()) {
OrderRow orderRow = orderRowList.get(0);
if (orderRow.getUnionId().equals(Long.parseLong(unionId))) {
content.append(orderUtil.getFormattedOrderInfo(orderRow, orderRow.getValidCode()));
} else {
content.append("订单不属于你,无法查询\r");
}
} else {
content.append("订单不存在\r");
}
contents.add(content);
content = new StringBuilder();
// 不统计已取消的订单
content.append("精准查询sku不统计已取消的订单:\r");
int[] validCodes = {-1, 3};
List<OrderRow> 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<OrderRow> 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<OrderRow> 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");
for (String s : split) {
content.append("https://item.jd.com/").append(s.trim()).append(".html").append("\r\n");
}
wxUtil.sendTextMessage(fromWxid, content.toString(), 1, fromWxid);
content = new StringBuilder();
content.append("手机端").append("\r\n");
for (String s : split) {
content.append("https://item.m.jd.com/product/").append(s.trim()).append(".html").append("\r\n");
}
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 {
sendOrderToWxByOrderJD("菜单", fromWxid);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if (!contents.isEmpty()) {
for (StringBuilder stringBuilder : contents) {
wxUtil.sendTextMessage(fromWxid, stringBuilder.toString(), 1, fromWxid);
}
}
}
/**
* 获取订单列表
*
* @param start 开始时间
* @param end 结束时间
* @return
* @throws Exception
*/
public UnionOpenOrderRowQueryResponse getUnionOpenOrderRowQueryResponse(LocalDateTime start, LocalDateTime end, Integer pageIndex, String appKey, String secretKey) throws Exception {
String startTime = start.format(DATE_TIME_FORMATTER);
String endTime = end.format(DATE_TIME_FORMATTER);
// 模拟 API 调用
//System.out.println("调用API - 从 " + startTime
// + " 到 " + endTime);
// 实际的 API 调用逻辑应在这里进行
JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, appKey, secretKey);
UnionOpenOrderRowQueryRequest request = new UnionOpenOrderRowQueryRequest();
OrderRowReq orderReq = new OrderRowReq();
orderReq.setPageIndex(pageIndex);
orderReq.setPageSize(200);
orderReq.setStartTime(startTime);
orderReq.setEndTime(endTime);
orderReq.setType(1);
request.setOrderReq(orderReq);
request.setVersion("1.0");
request.setSignmethod("md5");
// 时间戳格式为yyyy-MM-dd HH:mm:ss时区为GMT+8。API服务端允许客户端请求最大时间误差为10分钟
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
request.setTimestamp(simpleDateFormat.format(date));
return client.execute(request);
}
/**
* 接口描述:通过商品链接、领券链接、活动链接获取普通推广链接或优惠券二合一推广链接
* jd.union.open.promotion.bysubunionid.get
*/
String transfer(String url) throws Exception {
JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, LPF_APP_KEY_DG, LPF_SECRET_KEY_DG);
UnionOpenPromotionBysubunionidGetRequest request = new UnionOpenPromotionBysubunionidGetRequest();
PromotionCodeReq promotionCodeReq = new PromotionCodeReq();
request.setPromotionCodeReq(promotionCodeReq);
request.setVersion("1.0");
UnionOpenPromotionBysubunionidGetResponse response = client.execute(request);
/**
* {
* "jd_union_open_promotion_bysubunionid_get_responce": {
* "getResult": {
* "code": "200",
* "data": {
* "clickURL": "https://union-click.jd.com/jdc?e=XXXXXX p=XXXXXXXXXXX",
* "weChatShortLink": "#小程序://京小街/****",
* "jShortCommand": "短口令",
* "shortURL": "https://u.jd.com/XXXXX",
* "jCommand": "6.0复制整段话 http://JhT7V5wlKygHDK京口令内容#J6UFE5iMn***"
* },
* "message": "success"
* }
* }
* }
* */
String result = "";
if (Util.isNotEmpty(response)) {
if (response.getCode().equals("200")) {
result = response.getGetResult().getData().getShortURL();
}
} else {
result = null;
}
return result;
}
/**
* 消毒柜部分的业务逻辑
*/
@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 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;
//}
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(GIFT_MONEY_FLOW);
state.setCurrentStep(STEP_PRODUCT_LINK);
wxUtil.sendTextMessage(fromWxid, "请输入商品链接:", 1, fromWxid);
logger.info("进入礼金开通流程 - 商品链接步骤");
}
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 GIFT_MONEY_FLOW:
handleGiftMoneyFlow(fromWxid, message, state);
break;
case PRODUCT_ORDER_REGISTRATION:
handleProductOrderRegistration(fromWxid, message, state);
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 handleGiftMoneyFlow(String fromWxid, String message, UserInteractionState state) {
if ("礼金".equals(message)) {
state.reset(); // 重置流程
wxUtil.sendTextMessage(fromWxid, "流程已重置,请重新开始", 1, fromWxid);
return;
}
try {
switch (state.getCurrentStep()) {
case STEP_PRODUCT_LINK:
// 解析商品链接获取SKU
String skuId = parseSkuFromUrl(message);
Map<String, String> productInfo = queryProductInfo(skuId);
state.getCollectedFields().put("skuId", skuId);
state.getCollectedFields().put("productInfo", productInfo.get("name") + "\n价格" + productInfo.get("price"));
state.setCurrentStep(STEP_AMOUNT);
wxUtil.sendTextMessage(fromWxid, "商品信息:\n" + productInfo.get("name") + "\n当前价格" + productInfo.get("price") + "\n请输入开通金额", 1, fromWxid);
break;
case STEP_AMOUNT:
if (!isValidAmount(message)) {
wxUtil.sendTextMessage(fromWxid, "金额格式错误,请重新输入", 1, fromWxid);
return;
}
state.getCollectedFields().put("amount", message);
state.setCurrentStep(STEP_QUANTITY);
wxUtil.sendTextMessage(fromWxid, "请输入开通数量:", 1, fromWxid);
break;
case STEP_QUANTITY:
if (!isValidQuantity(message)) {
wxUtil.sendTextMessage(fromWxid, "数量格式错误,请重新输入", 1, fromWxid);
return;
}
state.getCollectedFields().put("quantity", message);
// 调用开通接口
boolean result = activateGiftMoney(state.getCollectedFields().get("skuId"), Double.parseDouble(state.getCollectedFields().get("amount")), Integer.parseInt(message));
String response = result ? "开通成功!" : "开通失败,请稍后重试";
wxUtil.sendTextMessage(fromWxid, response, 1, fromWxid);
state.reset(); // 完成流程
break;
}
} catch (Exception e) {
logger.error("礼金流程处理异常", e);
wxUtil.sendTextMessage(fromWxid, "系统异常,流程已终止", 1, fromWxid);
state.reset();
}
}
private String parseSkuFromUrl(String url) {
// 实现从URL中解析SKU的逻辑
return "123456"; // 示例返回值
}
private boolean isValidAmount(String input) {
return input.matches("^\\d+(\\.\\d{1,2})?$");
}
private Map<String, String> queryProductInfo(String skuId) {
// 调用京东商品查询API需要实现
return Map.of("name", "示例商品", "price", "299.00");
}
private boolean isValidQuantity(String input) {
return input.matches("^\\d+$");
}
private boolean activateGiftMoney(String skuId, double amount, int quantity) {
// 实现实际的开通接口调用
return true;
}
private void handleProductOrderRegistration(String fromWxid, String message, UserInteractionState state) {
switch (state.getCurrentProductOrderStep()) {
case STEP_ORDER_ID:
if (!message.matches("^\\d{10,20}$")) {
wxUtil.sendTextMessage(fromWxid, "⚠️ 订单号格式错误需10-20位数字", 1, fromWxid);
return;
}
state.getCollectedFields().put("orderId", message);
state.setCurrentProductOrderStep(STEP_PRODUCT_INFO);
wxUtil.sendTextMessage(fromWxid, "请输入商品信息(格式:商品名称-类型编号)\n类型对照1-家电 2-数码 3-服饰\n示例格力空调-1", 1, fromWxid);
break;
case STEP_PRODUCT_INFO:
String[] productInfo = message.split("-");
if (productInfo.length != 2 || !productInfo[1].matches("[1-3]")) {
wxUtil.sendTextMessage(fromWxid, "❌ 格式错误或类型编号无效", 1, fromWxid);
return;
}
state.getCollectedFields().put("skuName", productInfo[0]);
state.getCollectedFields().put("skuType", productInfo[1]);
state.setCurrentProductOrderStep(UserInteractionState.ProductOrderStep.STEP_RECIPIENT_INFO);
wxUtil.sendTextMessage(fromWxid, "请输入收件信息(格式:姓名-电话-地址)\n示例张三-13812345678-北京市朝阳区", 1, fromWxid);
break;
case STEP_RECIPIENT_INFO:
String[] recipientInfo = message.split("-");
if (recipientInfo.length < 3) {
wxUtil.sendTextMessage(fromWxid, "❌ 格式错误,请按示例格式输入", 1, fromWxid);
return;
}
state.getCollectedFields().put("recipientName", recipientInfo[0]);
state.getCollectedFields().put("recipientPhone", recipientInfo[1]);
state.getCollectedFields().put("recipientAddress", String.join("-", Arrays.copyOfRange(recipientInfo, 2, recipientInfo.length)));
// 生成确认信息
String confirmMsg = buildConfirmMessage(state);
wxUtil.sendTextMessage(fromWxid, confirmMsg, 1, fromWxid);
state.setCurrentProductOrderStep(STEP_REVIEW_CONFIRM);
break;
case STEP_REVIEW_CONFIRM:
if ("确认".equals(message)) {
boolean success = saveFullProductOrder(state, fromWxid);
wxUtil.sendTextMessage(fromWxid, success ? "✅ 订单登记成功!" : "❌ 保存失败,请联系管理员", 1, fromWxid);
state.reset();
} else {
state.setCurrentProductOrderStep(STEP_ORDER_ID);
wxUtil.sendTextMessage(fromWxid, "请重新输入订单号:", 1, fromWxid);
}
break;
}
}
private String buildConfirmMessage(UserInteractionState state) {
return "📋 请确认登记信息:\n" + "────────────────\n" + "▪ 订单号:" + state.getCollectedFields().get("orderId") + "\n" + "▪ 商品名称:" + state.getCollectedFields().get("skuName") + "\n" + "▪ 商品类型:" + getTypeDesc(state.getCollectedFields().get("skuType")) + "\n" + "▪ 收件人:" + state.getCollectedFields().get("recipientName") + "\n" + "▪ 联系方式:" + state.getCollectedFields().get("recipientPhone") + "\n" + "▪ 收货地址:" + state.getCollectedFields().get("recipientAddress") + "\n" + "────────────────\n" + "回复【确认】提交,其他内容重新开始";
}
private boolean saveFullProductOrder(UserInteractionState state, String fromWxid) {
try {
ProductOrder order = new ProductOrder();
order.setOrderId(state.getCollectedFields().get("orderId"));
order.setSkuName(state.getCollectedFields().get("skuName"));
order.setSkuType(Integer.valueOf(state.getCollectedFields().get("skuType")));
order.setRecipientName(state.getCollectedFields().get("recipientName"));
order.setRecipientPhone(state.getCollectedFields().get("recipientPhone"));
order.setRecipientAddress(state.getCollectedFields().get("recipientAddress"));
order.setOrderTime(new Date()); // 设置下单时间为当前时间
order.setWhoOrder(state.getCollectedFields().get("recipientName")); // 关联管理员信息
order.setIsReviewed(false); // 默认是否晒图登记
order.setIsCashbackReceived(false); // 默认是否返现到账
order.setFromWxid(fromWxid); // 设置当前交互的wxid
productOrderRepository.save(order);
logger.info("订单登记成功:{}", order);
return true;
} catch (Exception e) {
logger.error("订单保存异常:{}", e.getMessage());
return false;
}
}
private String getTypeDesc(String skuType) {
return switch (skuType) {
case "1" -> "家电";
case "2" -> "数码";
case "3" -> "服饰";
default -> "未知类型";
};
}
// 定义一个内部类来存储用户交互状态
@Getter
@Setter
static class UserInteractionState {
// 推荐使用枚举管理状态
public enum ProcessState {
INIT, GIFT_MONEY_FLOW, DISINFECTANT_CABINET,PRODUCT_ORDER_REGISTRATION
}
public enum GiftMoneyStep {
STEP_PRODUCT_LINK, STEP_AMOUNT, STEP_QUANTITY
}
// 在UserInteractionState类中新增步骤枚举
public enum ProductOrderStep {
STEP_ORDER_ID,
STEP_PRODUCT_INFO,
STEP_RECIPIENT_INFO,
STEP_REVIEW_CONFIRM,
STEP_CASHBACK_TRACK
}
private GiftMoneyStep currentStep; // 新增当前步骤字段
private String lastInteractionTime;
private ProcessState currentState;
private Map<String, String> collectedFields; // 用于存储收集到的字段值
private String currentField; // 当前正在询问的字段
private ProductOrderStep currentProductOrderStep;
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);
}
// UserInteractionState类缺少reset方法
public void reset() {
this.currentState = INIT;
this.collectedFields.clear();
this.currentStep = null;
updateLastInteractionTime();
}
}
// 限流异常类(需自定义)
public static class RateLimitExceededException extends RuntimeException {
public RateLimitExceededException(String message) {
super(message);
}
}
@Setter
@Getter
public static class OrderInfo {
private String skuName;
private Long count;
private Long orderId;
private Date orderDate;
}
// 统计指标DTO
@Getter
@AllArgsConstructor
class OrderStats {
private long totalOrders; // 总订单数
private long validOrders; // 有效订单数(不含取消)
private long paidOrders; // 已付款订单
private double paidCommission; // 已付款佣金
private long pendingOrders; // 待付款订单
private double pendingCommission; // 待付款佣金
private long canceledOrders; // 已取消订单
private long completedOrders; // 已完成订单
private double completedCommission;// 已完成佣金
private long violations; // 违规订单数
private double violationCommission;// 违规佣金
}
}