diff --git a/src/main/java/cn/van/business/util/JDUtil.java b/src/main/java/cn/van/business/util/JDUtil.java index a358cd2..b3544b8 100644 --- a/src/main/java/cn/van/business/util/JDUtil.java +++ b/src/main/java/cn/van/business/util/JDUtil.java @@ -474,11 +474,22 @@ public class JDUtil { private StringBuilder buildStatsContent(String title, OrderStats stats) { StringBuilder content = new StringBuilder(); - content.append(title).append(":\r\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()); + content.append(title).append(":\r\n") + .append("订单总数:").append(stats.getTotalOrders()) + .append("\r订单总数(不含取消):").append(stats.getValidOrders()) + .append("\r\n已付款:").append(stats.getPaidOrders()) + .append("\r已付款佣金:").append(String.format("%.2f", stats.getPaidCommission())) + .append("\r\n待付款:").append(stats.getPendingOrders()) + .append("\r待付款佣金:").append(String.format("%.2f", stats.getPendingCommission())) + .append("\r\n已取消:").append(stats.getCanceledOrders()) + .append("\r已完成:").append(stats.getCompletedOrders()) + .append("\r已完成佣金:").append(String.format("%.2f", stats.getCompletedCommission())) + .append("\r违规:").append(stats.getViolations()) + .append("\r违规佣金:").append(String.format("%.2f", stats.getViolationCommission())); return content; } + /** * 接收京粉指令指令 */ @@ -705,250 +716,251 @@ public class JDUtil { } } -/** - * 接收京粉指令指令 - * 高级菜单 - */ -public void sendOrderToWxByOrderJDAdvanced(String order, String fromWxid) { - int[] param = {-1}; - WXUtil.SuperAdmin superAdmin = super_admins.get(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("违规", ""); - Integer daysInt = 365; - if (Util.isNotEmpty(days)) { - daysInt = Integer.parseInt(days); - } - List filterOrdersByDays = filterOrdersByDate(orderRows, daysInt); - - content.append("违规排行:"); - 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, // ✅ 拼接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()); - info.setOrderId(orderRow.getOrderId()); - info.setOrderDate(orderRow.getOrderTime()); - return info; - }).collect(Collectors.groupingBy(OrderInfo::getSkuName)); - - List> sortedViolationCounts = skuIdViolationCountMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList()); - - Integer num = 0; - for (Map.Entry 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 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 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 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"); - 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(); + * 接收京粉指令指令 + * 高级菜单 + */ + public void sendOrderToWxByOrderJDAdvanced(String order, String fromWxid) { + int[] param = {-1}; + WXUtil.SuperAdmin superAdmin = super_admins.get(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("违规", ""); + Integer daysInt = 365; + if (Util.isNotEmpty(days)) { + daysInt = Integer.parseInt(days); + } + List filterOrdersByDays = filterOrdersByDate(orderRows, daysInt); + + content.append("违规排行:"); + 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, // ✅ 拼接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()); + info.setOrderId(orderRow.getOrderId()); + info.setOrderDate(orderRow.getOrderTime()); + return info; + }).collect(Collectors.groupingBy(OrderInfo::getSkuName)); + + List> sortedViolationCounts = skuIdViolationCountMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).collect(Collectors.toList()); + + Integer num = 0; + for (Map.Entry 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 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 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 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"); + 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); + } } - } else { - result = null; } - return result; -} + /** + * 获取订单列表 + * + * @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); -/** - * 消毒柜部分的业务逻辑 - */ -@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); + + 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(); } - } catch (Exception e) { - logger.error("Error parsing interaction state: {}", e.getMessage()); + } 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); // @@ -966,247 +978,274 @@ public void cleanUpTimeoutStates() { // 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); + 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 parsing interaction state: {}", e.getMessage()); - state = new UserInteractionState(); + logger.error("Error saving interaction state: {}", e.getMessage()); } } - 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 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; + // 新增礼金流程处理方法 + 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 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(); } - } 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 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 parseSkuFromUrl(String url) { + // 实现从URL中解析SKU的逻辑 + return "123456"; // 示例返回值 } -} -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 isValidAmount(String input) { + return input.matches("^\\d+(\\.\\d{1,2})?$"); + } -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 + private Map queryProductInfo(String skuId) { + // 调用京东商品查询API(需要实现) + return Map.of("name", "示例商品", "price", "299.00"); + } - productOrderRepository.save(order); - logger.info("订单登记成功:{}", order); + private boolean isValidQuantity(String input) { + return input.matches("^\\d+$"); + } + + private boolean activateGiftMoney(String skuId, double amount, int quantity) { + // 实现实际的开通接口调用 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 -> "未知类型"; - }; -} + 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 { + private GiftMoneyStep currentStep; // 新增当前步骤字段 + private String lastInteractionTime; + private ProcessState currentState; + private Map 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 enum ProcessState { - INIT, GIFT_MONEY_FLOW, DISINFECTANT_CABINET,PRODUCT_ORDER_REGISTRATION + 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, @@ -1215,54 +1254,28 @@ private String getTypeDesc(String skuType) { STEP_REVIEW_CONFIRM, STEP_CASHBACK_TRACK } - private GiftMoneyStep currentStep; // 新增当前步骤字段 - private String lastInteractionTime; - private ProcessState currentState; - private Map 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); + // 限流异常类(需自定义) + public static class RateLimitExceededException extends RuntimeException { + public RateLimitExceededException(String message) { + super(message); + } } - // UserInteractionState类缺少reset方法 - public void reset() { - this.currentState = INIT; - this.collectedFields.clear(); - this.currentStep = null; - updateLastInteractionTime(); + @Setter + @Getter + public static class OrderInfo { + private String skuName; + private Long count; + private Long orderId; + private Date orderDate; + } -} - -// 限流异常类(需自定义) -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