diff --git a/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/constants/RedisKeyConstant.java b/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/constants/RedisKeyConstant.java index d7742d8..b77221c 100644 --- a/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/constants/RedisKeyConstant.java +++ b/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/constants/RedisKeyConstant.java @@ -16,6 +16,12 @@ public class RedisKeyConstant { public static final String JNTYZX_VENUE_MSG_SEND_KEY = "jntyzx:order:venue:msg:send"; + private static final String JNTYZX_VENUE_SUBSCRIBE_KEY = "jntyzx:venue:subscribe:"; + + public static String getVenueSubscribeKey(String placeName) { + return JNTYZX_VENUE_SUBSCRIBE_KEY + placeName + ":" + getDate(); + } + public static String getDate() { LocalDate now = LocalDate.now(); return ":" + DateUtils.getDateFromDate(now); diff --git a/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/service/impl/OrderInfoServiceImpl.java b/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/service/impl/OrderInfoServiceImpl.java index 8e4b8ac..621f899 100644 --- a/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/service/impl/OrderInfoServiceImpl.java +++ b/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/service/impl/OrderInfoServiceImpl.java @@ -82,6 +82,10 @@ public class OrderInfoServiceImpl implements IJtOrderService { log.info("改会员卡被限制,不在请求,用户:{}", userTokenInfoDO.getName()); throw new BusinessException("会员卡被限制,不在请求"); } + if (orderResp.getMessage().contains("已有人预订")) { + log.info("该场地已被人预定,更换场地, 用户:{}", userTokenInfoDO.getName()); + redisService.set(RedisKeyConstant.getVenueSubscribeKey(venueInfoDOS.get(0).getPlaceName()), "true"); + } return false; } } diff --git a/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/utils/VenueInfoUtils.java b/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/utils/VenueInfoUtils.java index bb6bd06..8626560 100644 --- a/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/utils/VenueInfoUtils.java +++ b/xservice-core/src/main/java/com/xiang/app/modules/jntyzx/utils/VenueInfoUtils.java @@ -25,4 +25,17 @@ public class VenueInfoUtils { public static boolean get8210VenueInfo(SitePositionList sitePositionList) { return StringUtils.equals(sitePositionList.getSjName(), "20:00-21:00") || StringUtils.equals(sitePositionList.getSjName(), "21:00-22:00"); } + + public static int sortVenueInfo(String placeName) { + if (placeName.contains("十号")) { + return 0; + } + if (placeName.contains("二号")) { + return 1; + } + if (placeName.contains("九号")) { + return 2; + } + return 3; + } } diff --git a/xservice-server/src/main/java/com/xiang/app/schedule/jntyzx/JtVenuePickTask.java b/xservice-server/src/main/java/com/xiang/app/schedule/jntyzx/JtVenuePickTask.java new file mode 100644 index 0000000..585c64f --- /dev/null +++ b/xservice-server/src/main/java/com/xiang/app/schedule/jntyzx/JtVenuePickTask.java @@ -0,0 +1,128 @@ +package com.xiang.app.schedule.jntyzx; + +import com.xiang.app.modules.jntyzx.constants.RedisKeyConstant; +import com.xiang.app.modules.jntyzx.entity.pojo.UserTokenInfoDO; +import com.xiang.app.modules.jntyzx.entity.pojo.VenueInfoDO; +import com.xiang.app.modules.jntyzx.entity.resp.query.SitePositionList; +import com.xiang.app.modules.jntyzx.service.IJntyzxHttpService; +import com.xiang.app.modules.jntyzx.service.IJtOrderService; +import com.xiang.app.modules.jntyzx.service.IUserTokenInfoService; +import com.xiang.app.modules.jntyzx.utils.VenueInfoUtils; +import com.xiang.app.modules.jntyzx.utils.WeekendUtils; +import com.xiang.core.quartz.annotation.XxzJob; +import com.xiang.xmc.service.cache.service.IRedisService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 江体小程序场地捡漏任务 周日和周二 启动捡漏周一和周三的场地 + * @Author: xiang + * @Date: 2026-03-23 09:23 + */ +@Component +@Slf4j +@RequiredArgsConstructor +public class JtVenuePickTask { + + private final IJntyzxHttpService jntyzxHttpService; + private final IUserTokenInfoService userTokenInfoService; + private final IRedisService redisService; + private final IJtOrderService jtOrderService; + + + @XxzJob(name = "jtVenuePickTask") + public void handler() { + log.info("江体小程序场地捡漏,time:{}", System.currentTimeMillis()); + + List availableUser = userTokenInfoService.getAvailableUser(); + if (CollectionUtils.isEmpty(availableUser)) { + log.info("当前无可用用户查询场地信息!"); + return; + } + UserTokenInfoDO userTokenInfoDO = availableUser.get(0); + + if (Objects.isNull(userTokenInfoDO)) { + return; + } + String subscribeKey = RedisKeyConstant.JNTYZX_ORDER_CREATE_KEY + userTokenInfoDO.getName() + LocalDate.now(); + String subscribeValue = (String) redisService.get(subscribeKey); + if (StringUtils.isNotBlank(subscribeValue)) { + log.info("用户:{}今日已进行场地预定,不进行捡漏处理!", userTokenInfoDO.getName()); + return; + } + + String token = userTokenInfoDO.getToken(); + List sitePositionLists = jntyzxHttpService.queryAvailableTomorrow(WeekendUtils.isWeekend(), token); + sitePositionLists = sitePositionLists.stream() + .filter(item -> !item.getPlaceName().contains("小馆")) + .filter(VenueInfoUtils::get8210VenueInfo) + .filter(item -> StringUtils.equals(item.getContacts(), "0")).toList(); + if (CollectionUtils.isEmpty(sitePositionLists)) { + return; + } + Map> map = sitePositionLists.stream().map(item -> { + VenueInfoDO venueInfoDO = new VenueInfoDO(); + venueInfoDO.setPlaceName(item.getPlaceName()); + venueInfoDO.setPlaceId(item.getPlaceId()); + venueInfoDO.setScheduleId(Integer.valueOf(item.getScheduleId())); + venueInfoDO.setSjName(item.getSjName()); + venueInfoDO.setMoney(item.getMoney()); + venueInfoDO.setClassName(item.getClassName()); + venueInfoDO.setClassCode(item.getClassCode()); + venueInfoDO.setAppointments(item.getAppointments()); + venueInfoDO.setCTypeCode(item.getCtypeCode()); + return venueInfoDO; + }).collect(Collectors.groupingByConcurrent(VenueInfoDO::getPlaceName)); + + if (MapUtils.isEmpty(map)) { + log.info("暂无可下单场地,time:{}", System.currentTimeMillis()); + return; + } + + List users = userTokenInfoService.getCanOrderUser(); + if (CollectionUtils.isEmpty(users)) { + log.info("暂无可下单用户, time:{}", System.currentTimeMillis()); + return; + } + users.parallelStream().forEach(user -> { + try { + List placeNameList = map.keySet().stream().sorted(Comparator.comparing(VenueInfoUtils::sortVenueInfo)).toList(); + for (String placeName : placeNameList) { + List venueInfoDOList = map.get(placeName); + String valid = (String) redisService.get(RedisKeyConstant.getVenueSubscribeKey(placeName)); + if (StringUtils.isNotBlank(valid)) { + break; + } + boolean order = jtOrderService.createOrder(venueInfoDOList, user); + if (order) { + return; + } + try { + Thread.sleep(1250); + } catch (InterruptedException e) { + log.error("睡眠失败~~~"); + } + } + } catch (Exception e) { + // 关键点:异常只影响当前 user + log.error("createOrder 异常,user={}", user.getId(), e); + return; // 结束这个 user,不影响其他 user + } + }); + + + + + } +} diff --git a/xservice-server/src/main/java/com/xiang/app/schedule/jntyzx/JtVenueSubscribeTask.java b/xservice-server/src/main/java/com/xiang/app/schedule/jntyzx/JtVenueSubscribeTask.java index 80d9d03..298e1d9 100644 --- a/xservice-server/src/main/java/com/xiang/app/schedule/jntyzx/JtVenueSubscribeTask.java +++ b/xservice-server/src/main/java/com/xiang/app/schedule/jntyzx/JtVenueSubscribeTask.java @@ -1,6 +1,7 @@ package com.xiang.app.schedule.jntyzx; import com.xiang.app.common.service.dingtalk.JtDingTalkFactory; +import com.xiang.app.modules.jntyzx.constants.RedisKeyConstant; import com.xiang.app.modules.jntyzx.entity.pojo.UserTokenInfoDO; import com.xiang.app.modules.jntyzx.entity.pojo.VenueInfoDO; import com.xiang.app.modules.jntyzx.service.IJtOrderService; @@ -8,14 +9,17 @@ import com.xiang.app.modules.jntyzx.service.IUserTokenInfoService; import com.xiang.app.modules.jntyzx.service.IVenueService; import com.xiang.app.modules.jntyzx.utils.VenueInfoUtils; import com.xiang.core.quartz.annotation.XxzJob; +import com.xiang.xmc.service.cache.service.IRedisService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -30,6 +34,7 @@ public class JtVenueSubscribeTask { private final IJtOrderService jtOrderService; private final IVenueService venueService; private final JtDingTalkFactory jtDingTalkFactory; + private final IRedisService redisService; @XxzJob(name = "jtVenueSubscribeTask") @GetMapping("/jtVenueSubscribeTask") @@ -51,9 +56,14 @@ public class JtVenueSubscribeTask { users.parallelStream().forEach(user -> { try { - for (String placeName : venueInfoMap.keySet()) { + List placeNameList = venueInfoMap.keySet().stream().sorted(Comparator.comparing(VenueInfoUtils::sortVenueInfo)).toList(); + for (String placeName : placeNameList) { List venueInfoDOList = venueInfoMap.get(placeName); for (int i = 0; i < 10; i++) { + String valid = (String) redisService.get(RedisKeyConstant.getVenueSubscribeKey(placeName)); + if (StringUtils.isNotBlank(valid)) { + break; + } boolean order = jtOrderService.createOrder(venueInfoDOList, user); if (order) { return;