|
@@ -1,6 +1,5 @@
|
|
|
package com.sf.service.impl;
|
|
|
|
|
|
-import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import com.alibaba.fastjson2.JSON;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
@@ -9,15 +8,18 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.google.common.collect.Lists;
|
|
|
import com.sf.dto.SeatClassDTO;
|
|
|
import com.sf.dto.TicketListDTO;
|
|
|
+import com.sf.dto.domain.RouteDTO;
|
|
|
import com.sf.dto.req.TicketPageQueryReqDTO;
|
|
|
import com.sf.dto.resp.TicketPageQueryRespDTO;
|
|
|
-import com.sf.entity.TicketDO;
|
|
|
-import com.sf.entity.TrainStationPriceDO;
|
|
|
-import com.sf.mapper.TicketMapper;
|
|
|
+import com.sf.entity.*;
|
|
|
+import com.sf.mapper.*;
|
|
|
import com.sf.service.TicketService;
|
|
|
+import com.sf.util.DateUtil;
|
|
|
+import com.sf.util.StationCalculateUtil;
|
|
|
import com.sf.util.TimeStringComparator;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import org.opengoofy.index12306.framework.starter.cache.DistributedCache;
|
|
|
+import org.opengoofy.index12306.framework.starter.cache.toolkit.CacheUtil;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
import org.springframework.stereotype.Service;
|
|
@@ -30,16 +32,167 @@ import java.util.stream.Collectors;
|
|
|
|
|
|
import static com.sf.constant.Index12306Constant.ADVANCE_TICKET_DAY;
|
|
|
import static com.sf.constant.RedisKeyConstant.*;
|
|
|
+import static com.sf.util.DateUtil.convertDateToLocalTime;
|
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
@Service
|
|
|
public class TicketServiceImpl extends ServiceImpl<TicketMapper, TicketDO> implements TicketService {
|
|
|
|
|
|
private final DistributedCache distributedCache;
|
|
|
+ private final StationMapper stationMapper;
|
|
|
+ private final TrainStationRelationMapper trainStationRelationMapper;
|
|
|
+ private final TrainMapper trainMapper;
|
|
|
+ private final TrainStationPriceMapper trainStationPriceMapper;
|
|
|
+ private final TrainStationMapper trainStationMapper;
|
|
|
+ private final SeatMapper seatMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TicketPageQueryRespDTO pageListTicketQueryByMysql(TicketPageQueryReqDTO requestParam) {
|
|
|
+ System.out.println("TicketPageQueryRespDTO pageListTicketQueryByMysql");
|
|
|
+ // 准备stationDetails 找到出发站和到达站的名字
|
|
|
+ List<StationDO> stationDOList = stationMapper.selectList(Wrappers.emptyWrapper());
|
|
|
+ Map<String, String> regionTrainStationMap = new HashMap<>();
|
|
|
+ stationDOList.forEach(each -> regionTrainStationMap.put(each.getCode(), each.getRegionName()));
|
|
|
+
|
|
|
+ List<Object> stationDetails = new ArrayList<>();
|
|
|
+ stationDetails.add(regionTrainStationMap.get(requestParam.getFromStation()));
|
|
|
+ stationDetails.add(regionTrainStationMap.get(requestParam.getToStation()));
|
|
|
+
|
|
|
+ // 然后将两个名字作为参数 去 train_station_relation表中查询
|
|
|
+ LambdaQueryWrapper<TrainStationRelationDO> queryWrapper = Wrappers.lambdaQuery(TrainStationRelationDO.class)
|
|
|
+ .eq(TrainStationRelationDO::getStartRegion, stationDetails.get(0))
|
|
|
+ .eq(TrainStationRelationDO::getEndRegion, stationDetails.get(1));
|
|
|
+ List<TrainStationRelationDO> trainStationRelationList = trainStationRelationMapper.selectList(queryWrapper);
|
|
|
+
|
|
|
+ // 将TrainDO和TrainStationRelationDO中的数据整合在一起
|
|
|
+ List<TicketListDTO> seatResults = new ArrayList<>();
|
|
|
+ Map<Object, Object> regionTrainStationAllMap = new HashMap<>();
|
|
|
+ for (TrainStationRelationDO each : trainStationRelationList) {
|
|
|
+ TrainDO trainDO = trainMapper.selectById(each.getTrainId());
|
|
|
+
|
|
|
+ TicketListDTO result = new TicketListDTO();
|
|
|
+ result.setTrainId(String.valueOf(trainDO.getId()));
|
|
|
+ result.setTrainNumber(trainDO.getTrainNumber());
|
|
|
+ result.setDepartureTime(convertDateToLocalTime(each.getDepartureTime(), "HH:mm"));
|
|
|
+ result.setArrivalTime(convertDateToLocalTime(each.getArrivalTime(), "HH:mm"));
|
|
|
+ result.setDuration(DateUtil.calculateHourDifference(each.getDepartureTime(), each.getArrivalTime()));
|
|
|
+ result.setDeparture(each.getDeparture());
|
|
|
+ result.setArrival(each.getArrival());
|
|
|
+ result.setDepartureFlag(each.getDepartureFlag());
|
|
|
+ result.setArrivalFlag(each.getArrivalFlag());
|
|
|
+ result.setTrainType(trainDO.getTrainType());
|
|
|
+ result.setTrainBrand(trainDO.getTrainBrand());
|
|
|
+ if (StrUtil.isNotBlank(trainDO.getTrainTag())) {
|
|
|
+ result.setTrainTags(StrUtil.split(trainDO.getTrainTag(), ","));
|
|
|
+ }
|
|
|
+ long betweenDay = cn.hutool.core.date.DateUtil.betweenDay(each.getDepartureTime(), each.getArrivalTime(), false);
|
|
|
+ result.setDaysArrived((int) betweenDay);
|
|
|
+ result.setSaleStatus(new Date().after(trainDO.getSaleTime()) ? 0 : 1);
|
|
|
+ result.setSaleTime(convertDateToLocalTime(trainDO.getSaleTime(), "MM-dd HH:mm"));
|
|
|
+ seatResults.add(result);
|
|
|
+ regionTrainStationAllMap.put(
|
|
|
+ // TrainId_Departure_Arrival
|
|
|
+ CacheUtil.buildKey(String.valueOf(each.getTrainId()), each.getDeparture(), each.getArrival()),
|
|
|
+ JSON.toJSONString(result));
|
|
|
+ }
|
|
|
+ // 按照出发时间排序
|
|
|
+ seatResults = seatResults.stream().sorted(new TimeStringComparator()).toList();
|
|
|
+
|
|
|
+ for (TicketListDTO each : seatResults) {
|
|
|
+ LambdaQueryWrapper<TrainStationPriceDO> trainStationPriceQueryWrapper = Wrappers.lambdaQuery(TrainStationPriceDO.class)
|
|
|
+ .eq(TrainStationPriceDO::getDeparture, each.getDeparture())
|
|
|
+ .eq(TrainStationPriceDO::getArrival, each.getArrival())
|
|
|
+ .eq(TrainStationPriceDO::getTrainId, each.getTrainId());
|
|
|
+ List<TrainStationPriceDO> trainStationPriceDOList = trainStationPriceMapper.selectList(trainStationPriceQueryWrapper);
|
|
|
+
|
|
|
+ List<SeatClassDTO> seatClassList = new ArrayList<>();
|
|
|
+ trainStationPriceDOList.forEach(item -> {
|
|
|
+ String trainId = each.getTrainId();
|
|
|
+ String departure = item.getDeparture();
|
|
|
+ String arrival = item.getArrival();
|
|
|
+
|
|
|
+ // Map<String, String> seatMarginMap = seatMarginCacheLoader.load(
|
|
|
+ // String.valueOf(each.getTrainId()), seatType, item.getDeparture(), item.getArrival());
|
|
|
+ Map<String, Map<String, String>> trainStationRemainingTicketMaps = new LinkedHashMap<>();
|
|
|
+ String keySuffix = CacheUtil.buildKey(trainId, departure, arrival);
|
|
|
+ TrainDO trainDO = trainMapper.selectById(each.getTrainId());
|
|
|
+ LambdaQueryWrapper<TrainStationDO> queryWrapperNew = Wrappers.lambdaQuery(TrainStationDO.class)
|
|
|
+ .eq(TrainStationDO::getTrainId, trainId)
|
|
|
+ .select(TrainStationDO::getDeparture);
|
|
|
+ List<TrainStationDO> trainStationDOList = trainStationMapper.selectList(queryWrapperNew);
|
|
|
+ List<String> trainStationAllList = trainStationDOList.stream().map(TrainStationDO::getDeparture).collect(Collectors.toList());
|
|
|
+ // 计算出发站和终点站中间的站点
|
|
|
+ List<RouteDTO> routeDTOList = StationCalculateUtil.throughStation(trainStationAllList, departure, arrival);
|
|
|
+
|
|
|
+ // 假设不为空
|
|
|
+ switch (trainDO.getTrainType()) {
|
|
|
+ // TODO 通过已有列车类型座位枚举重构
|
|
|
+ case 0 -> {
|
|
|
+ for (RouteDTO routeDTO : routeDTOList) {
|
|
|
+ Map<String, String> trainStationRemainingTicket = new LinkedHashMap<>();
|
|
|
+ trainStationRemainingTicket.put("0", selectSeatMargin(trainId, 0, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("1", selectSeatMargin(trainId, 1, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("2", selectSeatMargin(trainId, 2, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ String actualKeySuffix = CacheUtil.buildKey(trainId, routeDTO.getStartStation(), routeDTO.getEndStation());
|
|
|
+ trainStationRemainingTicketMaps.put(TRAIN_STATION_REMAINING_TICKET + actualKeySuffix, trainStationRemainingTicket);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case 1 -> {
|
|
|
+ for (RouteDTO routeDTO : routeDTOList) {
|
|
|
+ Map<String, String> trainStationRemainingTicket = new LinkedHashMap<>();
|
|
|
+ trainStationRemainingTicket.put("3", selectSeatMargin(trainId, 3, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("4", selectSeatMargin(trainId, 4, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("5", selectSeatMargin(trainId, 5, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("13", selectSeatMargin(trainId, 13, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ String actualKeySuffix = CacheUtil.buildKey(trainId, routeDTO.getStartStation(), routeDTO.getEndStation());
|
|
|
+ trainStationRemainingTicketMaps.put(TRAIN_STATION_REMAINING_TICKET + actualKeySuffix, trainStationRemainingTicket);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case 2 -> {
|
|
|
+ for (RouteDTO routeDTO : routeDTOList) {
|
|
|
+ Map<String, String> trainStationRemainingTicket = new LinkedHashMap<>();
|
|
|
+ trainStationRemainingTicket.put("6", selectSeatMargin(trainId, 6, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("7", selectSeatMargin(trainId, 7, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("8", selectSeatMargin(trainId, 8, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ trainStationRemainingTicket.put("13", selectSeatMargin(trainId, 13, routeDTO.getStartStation(), routeDTO.getEndStation()));
|
|
|
+ String actualKeySuffix = CacheUtil.buildKey(trainId, routeDTO.getStartStation(), routeDTO.getEndStation());
|
|
|
+ trainStationRemainingTicketMaps.put(TRAIN_STATION_REMAINING_TICKET + actualKeySuffix, trainStationRemainingTicket);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, String> seatMarginMap = trainStationRemainingTicketMaps.get(TRAIN_STATION_REMAINING_TICKET + keySuffix);
|
|
|
+ int quantity = Integer.parseInt(seatMarginMap.get(String.valueOf(item.getSeatType())));
|
|
|
+
|
|
|
+ seatClassList.add(new SeatClassDTO(
|
|
|
+ item.getSeatType(), quantity,
|
|
|
+ new BigDecimal(item.getPrice()).divide(new BigDecimal("100"), 1, RoundingMode.HALF_UP), false));
|
|
|
+ });
|
|
|
+ each.setSeatClassList(seatClassList);
|
|
|
+ }
|
|
|
+
|
|
|
+ return TicketPageQueryRespDTO.builder()
|
|
|
+ .trainList(seatResults)
|
|
|
+ .departureStationList(buildDepartureStationList(seatResults))
|
|
|
+ .arrivalStationList(buildArrivalStationList(seatResults))
|
|
|
+ .trainBrandList(buildTrainBrandList(seatResults))
|
|
|
+ .seatClassTypeList(buildSeatClassList(seatResults))
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String selectSeatMargin(String trainId, Integer type, String departure, String arrival) {
|
|
|
+ LambdaQueryWrapper<SeatDO> queryWrapper = Wrappers.lambdaQuery(SeatDO.class)
|
|
|
+ .eq(SeatDO::getTrainId, trainId)
|
|
|
+ .eq(SeatDO::getSeatType, type)
|
|
|
+ .eq(SeatDO::getSeatStatus, 0)
|
|
|
+ .eq(SeatDO::getStartStation, departure)
|
|
|
+ .eq(SeatDO::getEndStation, arrival);
|
|
|
+ return String.valueOf(seatMapper.selectCount(queryWrapper));
|
|
|
+ }
|
|
|
|
|
|
// http://localhost:9000/api/ticket-service/ticket/query?fromStation=BJP&toStation=HZH&departureDate=2024-05-15
|
|
|
@Override
|
|
|
- public TicketPageQueryRespDTO pageListTicketQueryV1(TicketPageQueryReqDTO requestParam) {
|
|
|
+ public TicketPageQueryRespDTO pageListTicketQueryByRedis(TicketPageQueryReqDTO requestParam) {
|
|
|
|
|
|
StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) distributedCache.getInstance();
|
|
|
|
|
@@ -88,8 +241,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, TicketDO> imple
|
|
|
// 获取每个席别对应的票数
|
|
|
Object quantityObj = stringRedisTemplate.opsForHash().get(TRAIN_STATION_REMAINING_TICKET + keySuffix, seatType);
|
|
|
int quantity = Optional.ofNullable(quantityObj).map(Object::toString).map(Integer::parseInt).get();
|
|
|
- seatClassList.add(new SeatClassDTO(
|
|
|
- item.getSeatType(), quantity,
|
|
|
+ seatClassList.add(new SeatClassDTO(item.getSeatType(), quantity,
|
|
|
new BigDecimal(item.getPrice()).divide(new BigDecimal("100"), 1, RoundingMode.HALF_UP),
|
|
|
false));
|
|
|
});
|