TicketServiceImpl.java 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. package com.sf.service.impl;
  2. import cn.hutool.core.util.StrUtil;
  3. import com.alibaba.fastjson2.JSON;
  4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  5. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  6. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  7. import com.google.common.collect.Lists;
  8. import com.sf.dto.SeatClassDTO;
  9. import com.sf.dto.TicketListDTO;
  10. import com.sf.dto.domain.RouteDTO;
  11. import com.sf.dto.remote.TicketOrderCreateRemoteReqDTO;
  12. import com.sf.dto.remote.TicketOrderItemCreateRemoteReqDTO;
  13. import com.sf.dto.req.PurchaseTicketReqDTO;
  14. import com.sf.dto.req.TicketPageQueryReqDTO;
  15. import com.sf.dto.resp.TicketOrderDetailRespDTO;
  16. import com.sf.dto.resp.TicketPageQueryRespDTO;
  17. import com.sf.dto.resp.TicketPurchaseRespDTO;
  18. import com.sf.dto.resp.TrainPurchaseTicketRespDTO;
  19. import com.sf.entity.*;
  20. import com.sf.mapper.*;
  21. import com.sf.remote.TicketOrderRemoteService;
  22. import com.sf.service.TicketService;
  23. import com.sf.service.handler.TrainSeatTypeSelector;
  24. import com.sf.util.DateUtil;
  25. import com.sf.util.StationCalculateUtil;
  26. import com.sf.util.TimeStringComparator;
  27. import lombok.RequiredArgsConstructor;
  28. import lombok.extern.slf4j.Slf4j;
  29. import org.opengoofy.index12306.framework.starter.cache.DistributedCache;
  30. import org.opengoofy.index12306.framework.starter.cache.toolkit.CacheUtil;
  31. import org.opengoofy.index12306.framework.starter.convention.exception.ServiceException;
  32. import org.opengoofy.index12306.framework.starter.convention.result.Result;
  33. import org.opengoofy.index12306.frameworks.starter.user.core.UserContext;
  34. import org.springframework.beans.factory.annotation.Autowired;
  35. import org.springframework.data.redis.core.StringRedisTemplate;
  36. import org.springframework.stereotype.Service;
  37. import java.math.BigDecimal;
  38. import java.math.RoundingMode;
  39. import java.util.*;
  40. import java.util.concurrent.TimeUnit;
  41. import java.util.stream.Collectors;
  42. import static com.sf.constant.Index12306Constant.ADVANCE_TICKET_DAY;
  43. import static com.sf.constant.RedisKeyConstant.*;
  44. import static com.sf.util.DateUtil.convertDateToLocalTime;
  45. @Slf4j
  46. @RequiredArgsConstructor
  47. @Service
  48. public class TicketServiceImpl extends ServiceImpl<TicketMapper, TicketDO> implements TicketService {
  49. private final DistributedCache distributedCache;
  50. private final StationMapper stationMapper;
  51. private final TrainStationRelationMapper trainStationRelationMapper;
  52. private final TrainMapper trainMapper;
  53. private final TrainStationPriceMapper trainStationPriceMapper;
  54. private final TrainStationMapper trainStationMapper;
  55. private final SeatMapper seatMapper;
  56. private final TrainSeatTypeSelector trainSeatTypeSelector;
  57. private final TicketOrderRemoteService ticketOrderRemoteService;
  58. @Override
  59. public TicketPageQueryRespDTO pageListTicketQueryByMysql(TicketPageQueryReqDTO requestParam) {
  60. System.out.println("TicketPageQueryRespDTO pageListTicketQueryByMysql");
  61. // 准备stationDetails 找到出发站和到达站的名字
  62. // INSERT INTO `t_station` (`id`, `code`, `name`, `spell`, `region`, `region_name`, `create_time`, `update_time`, `del_flag`)
  63. // VALUES
  64. // (1, 'VNP', '北京南', 'beijingnan', 'BJP', '北京', '2023-06-01 20:54:00', '2023-06-01 20:54:00', 0);
  65. List<StationDO> stationDOList = stationMapper.selectList(Wrappers.emptyWrapper());
  66. Map<String, String> regionTrainStationMap = new HashMap<>();
  67. stationDOList.forEach(each -> regionTrainStationMap.put(each.getCode(), each.getRegionName()));
  68. List<Object> stationDetails = new ArrayList<>();
  69. stationDetails.add(regionTrainStationMap.get(requestParam.getFromStation()));
  70. stationDetails.add(regionTrainStationMap.get(requestParam.getToStation()));
  71. // LambdaQueryWrapper<StationDO> stationWrapper = new LambdaQueryWrapper<>();
  72. // stationWrapper.in(StationDO::getCode, List.of(requestParam.getFromStation(), requestParam.getToStation()));
  73. // List<StationDO> stationDOS = stationMapper.selectList(stationWrapper);
  74. // 这里可以直接将code值传入数据库 就不需要再转化成map了
  75. // 然后将两个名字作为参数 去 train_station_relation表中查询
  76. // INSERT INTO `t_train_station_relation` (`id`, `train_id`, `departure`, `arrival`, `start_region`, `end_region`, `departure_flag`, `arrival_flag`, `departure_time`, `arrival_time`, `create_time`, `update_time`, `del_flag`)
  77. // VALUES
  78. // (1665025584123056128, 1, '北京南', '济南西', '北京', '济南', 1, 0, '2023-06-01 09:56:00', '2023-06-01 11:19:00', '2023-06-04 00:00:09', '2023-06-04 00:00:09', 0);
  79. // select * from t_train_station_relation where start_region = '北京' and end_region = '杭州'
  80. LambdaQueryWrapper<TrainStationRelationDO> queryWrapper = Wrappers.lambdaQuery(TrainStationRelationDO.class)
  81. .eq(TrainStationRelationDO::getStartRegion, stationDetails.get(0))
  82. .eq(TrainStationRelationDO::getEndRegion, stationDetails.get(1));
  83. List<TrainStationRelationDO> trainStationRelationList = trainStationRelationMapper.selectList(queryWrapper);
  84. // 将TrainDO和TrainStationRelationDO中的数据整合在一起
  85. List<TicketListDTO> seatResults = new ArrayList<>();
  86. // Map<Object, Object> regionTrainStationAllMap = new HashMap<>();
  87. // 遍历找到的车次 (4个)
  88. for (TrainStationRelationDO each : trainStationRelationList) {
  89. // INSERT INTO `t_train` (`id`, `train_number`, `train_type`, `train_tag`, `train_brand`, `start_station`, `end_station`, `start_region`, `end_region`, `sale_time`, `sale_status`, `departure_time`, `arrival_time`, `create_time`, `update_time`, `del_flag`)
  90. // VALUES
  91. // (1, 'G35', 0, '0,1,2', '0,6', '北京南', '宁波', '北京', '宁波', '2023-05-15 14:30:00', 0, '2023-06-01 09:56:00', '2023-06-01 15:14:00', '2023-06-01 20:45:00', '2023-06-01 20:45:00', 0);
  92. TrainDO trainDO = trainMapper.selectById(each.getTrainId());
  93. TicketListDTO result = new TicketListDTO();
  94. result.setTrainId(String.valueOf(trainDO.getId()));
  95. result.setTrainNumber(trainDO.getTrainNumber());
  96. result.setDepartureTime(convertDateToLocalTime(each.getDepartureTime(), "HH:mm"));
  97. result.setArrivalTime(convertDateToLocalTime(each.getArrivalTime(), "HH:mm"));
  98. result.setDuration(DateUtil.calculateHourDifference(each.getDepartureTime(), each.getArrivalTime()));
  99. result.setDeparture(each.getDeparture());
  100. result.setArrival(each.getArrival());
  101. result.setDepartureFlag(each.getDepartureFlag());
  102. result.setArrivalFlag(each.getArrivalFlag());
  103. result.setTrainType(trainDO.getTrainType());
  104. result.setTrainBrand(trainDO.getTrainBrand());
  105. if (StrUtil.isNotBlank(trainDO.getTrainTag())) {
  106. result.setTrainTags(StrUtil.split(trainDO.getTrainTag(), ","));
  107. }
  108. long betweenDay = cn.hutool.core.date.DateUtil.betweenDay(each.getDepartureTime(), each.getArrivalTime(), false);
  109. result.setDaysArrived((int) betweenDay);
  110. result.setSaleStatus(new Date().after(trainDO.getSaleTime()) ? 0 : 1);
  111. result.setSaleTime(convertDateToLocalTime(trainDO.getSaleTime(), "MM-dd HH:mm"));
  112. seatResults.add(result);
  113. // regionTrainStationAllMap.put(
  114. // // TrainId_Departure_Arrival
  115. // CacheUtil.buildKey(String.valueOf(each.getTrainId()), each.getDeparture(), each.getArrival()),
  116. // JSON.toJSONString(result));
  117. }
  118. // 按照出发时间排序
  119. seatResults = seatResults.stream().sorted(new TimeStringComparator()).toList();
  120. for (TicketListDTO each : seatResults) {
  121. // INSERT INTO `t_train_station_relation` (`id`, `train_id`, `departure`, `arrival`, `start_region`, `end_region`, `departure_flag`, `arrival_flag`, `departure_time`, `arrival_time`, `create_time`, `update_time`, `del_flag`)
  122. // VALUES
  123. // (1665025584206942208, 1, '北京南', '杭州东', '北京', '杭州', 1, 0, '2023-06-01 09:56:00', '2023-06-01 14:26:00', '2023-06-04 00:00:09', '2023-06-04 00:00:09', 0);
  124. // select * from t_train_station_price where departure = '北京南' and arrival = '杭州东' and train_id = '1'
  125. LambdaQueryWrapper<TrainStationPriceDO> trainStationPriceQueryWrapper = Wrappers.lambdaQuery(TrainStationPriceDO.class)
  126. .eq(TrainStationPriceDO::getDeparture, each.getDeparture())
  127. .eq(TrainStationPriceDO::getArrival, each.getArrival())
  128. .eq(TrainStationPriceDO::getTrainId, each.getTrainId());
  129. List<TrainStationPriceDO> trainStationPriceDOList = trainStationPriceMapper.selectList(trainStationPriceQueryWrapper);
  130. // 查询结果
  131. // INSERT INTO `t_train_station_price` (`id`, `train_id`, `departure`, `arrival`, `seat_type`, `price`, `create_time`, `update_time`, `del_flag`)
  132. // VALUES
  133. // (1664877136516444160, 1, '北京南', '杭州东', 0, 231300, '2023-06-03 14:10:16', '2023-06-03 14:10:16', 0);
  134. // 这里是3条 对应商务座、一等座、二等座的价格
  135. List<SeatClassDTO> seatClassList = new ArrayList<>();
  136. trainStationPriceDOList.forEach(item -> {
  137. String trainId = each.getTrainId();
  138. String departure = item.getDeparture();
  139. String arrival = item.getArrival();
  140. // Map<String, String> seatMarginMap = seatMarginCacheLoader.load(
  141. // String.valueOf(each.getTrainId()), seatType, item.getDeparture(), item.getArrival());
  142. Map<String, Map<String, String>> trainStationRemainingTicketMaps = new LinkedHashMap<>();
  143. // INSERT INTO `t_train` (`id`, `train_number`, `train_type`, `train_tag`, `train_brand`, `start_station`, `end_station`, `start_region`, `end_region`, `sale_time`, `sale_status`, `departure_time`, `arrival_time`, `create_time`, `update_time`, `del_flag`)
  144. // VALUES
  145. // (1, 'G35', 0, '0,1,2', '0,6', '北京南', '宁波', '北京', '宁波', '2023-05-15 14:30:00', 0, '2023-06-01 09:56:00', '2023-06-01 15:14:00', '2023-06-01 20:45:00', '2023-06-01 20:45:00', 0);
  146. TrainDO trainDO = trainMapper.selectById(each.getTrainId());
  147. // select departure from t_train_station where train_id = '1'
  148. LambdaQueryWrapper<TrainStationDO> queryWrapperNew = Wrappers.lambdaQuery(TrainStationDO.class)
  149. .eq(TrainStationDO::getTrainId, trainId)
  150. .select(TrainStationDO::getDeparture);
  151. List<TrainStationDO> trainStationDOList = trainStationMapper.selectList(queryWrapperNew);
  152. // 把查询到的出发站放在这个list中
  153. List<String> trainStationAllList = trainStationDOList.stream().map(TrainStationDO::getDeparture).collect(Collectors.toList());
  154. // 计算出发站和终点站中间的站点
  155. List<RouteDTO> routeDTOList = StationCalculateUtil.throughStation(trainStationAllList, departure, arrival);
  156. // 假设不为空
  157. // G高铁是0 D动车1 Z直达是2
  158. switch (trainDO.getTrainType()) {
  159. case 0 -> {
  160. for (RouteDTO routeDTO : routeDTOList) {
  161. Map<String, String> trainStationRemainingTicket = new LinkedHashMap<>();
  162. trainStationRemainingTicket.put("0", selectSeatMargin(trainId, 0, routeDTO.getStartStation(), routeDTO.getEndStation()));
  163. trainStationRemainingTicket.put("1", selectSeatMargin(trainId, 1, routeDTO.getStartStation(), routeDTO.getEndStation()));
  164. trainStationRemainingTicket.put("2", selectSeatMargin(trainId, 2, routeDTO.getStartStation(), routeDTO.getEndStation()));
  165. String actualKeySuffix = CacheUtil.buildKey(trainId, routeDTO.getStartStation(), routeDTO.getEndStation());
  166. trainStationRemainingTicketMaps.put(TRAIN_STATION_REMAINING_TICKET + actualKeySuffix, trainStationRemainingTicket);
  167. }
  168. }
  169. case 1 -> {
  170. for (RouteDTO routeDTO : routeDTOList) {
  171. Map<String, String> trainStationRemainingTicket = new LinkedHashMap<>();
  172. trainStationRemainingTicket.put("3", selectSeatMargin(trainId, 3, routeDTO.getStartStation(), routeDTO.getEndStation()));
  173. trainStationRemainingTicket.put("4", selectSeatMargin(trainId, 4, routeDTO.getStartStation(), routeDTO.getEndStation()));
  174. trainStationRemainingTicket.put("5", selectSeatMargin(trainId, 5, routeDTO.getStartStation(), routeDTO.getEndStation()));
  175. trainStationRemainingTicket.put("13", selectSeatMargin(trainId, 13, routeDTO.getStartStation(), routeDTO.getEndStation()));
  176. String actualKeySuffix = CacheUtil.buildKey(trainId, routeDTO.getStartStation(), routeDTO.getEndStation());
  177. trainStationRemainingTicketMaps.put(TRAIN_STATION_REMAINING_TICKET + actualKeySuffix, trainStationRemainingTicket);
  178. }
  179. }
  180. case 2 -> {
  181. for (RouteDTO routeDTO : routeDTOList) {
  182. Map<String, String> trainStationRemainingTicket = new LinkedHashMap<>();
  183. trainStationRemainingTicket.put("6", selectSeatMargin(trainId, 6, routeDTO.getStartStation(), routeDTO.getEndStation()));
  184. trainStationRemainingTicket.put("7", selectSeatMargin(trainId, 7, routeDTO.getStartStation(), routeDTO.getEndStation()));
  185. trainStationRemainingTicket.put("8", selectSeatMargin(trainId, 8, routeDTO.getStartStation(), routeDTO.getEndStation()));
  186. trainStationRemainingTicket.put("13", selectSeatMargin(trainId, 13, routeDTO.getStartStation(), routeDTO.getEndStation()));
  187. String actualKeySuffix = CacheUtil.buildKey(trainId, routeDTO.getStartStation(), routeDTO.getEndStation());
  188. trainStationRemainingTicketMaps.put(TRAIN_STATION_REMAINING_TICKET + actualKeySuffix, trainStationRemainingTicket);
  189. }
  190. }
  191. }
  192. String keySuffix = CacheUtil.buildKey(trainId, departure, arrival);
  193. Map<String, String> seatMarginMap = trainStationRemainingTicketMaps.get(TRAIN_STATION_REMAINING_TICKET + keySuffix);
  194. int quantity = Integer.parseInt(seatMarginMap.get(String.valueOf(item.getSeatType())));
  195. seatClassList.add(new SeatClassDTO(
  196. item.getSeatType(), quantity,
  197. new BigDecimal(item.getPrice()).divide(new BigDecimal("100"), 1, RoundingMode.HALF_UP), false));
  198. });
  199. each.setSeatClassList(seatClassList);
  200. }
  201. return TicketPageQueryRespDTO.builder()
  202. .trainList(seatResults)
  203. .departureStationList(buildDepartureStationList(seatResults))
  204. .arrivalStationList(buildArrivalStationList(seatResults))
  205. .trainBrandList(buildTrainBrandList(seatResults))
  206. .seatClassTypeList(buildSeatClassList(seatResults))
  207. .build();
  208. }
  209. private String selectSeatMargin(String trainId, Integer type, String departure, String arrival) {
  210. LambdaQueryWrapper<SeatDO> queryWrapper = Wrappers.lambdaQuery(SeatDO.class)
  211. .eq(SeatDO::getTrainId, trainId)
  212. .eq(SeatDO::getSeatType, type)
  213. .eq(SeatDO::getSeatStatus, 0)
  214. .eq(SeatDO::getStartStation, departure)
  215. .eq(SeatDO::getEndStation, arrival);
  216. return String.valueOf(seatMapper.selectCount(queryWrapper));
  217. }
  218. // http://localhost:9000/api/ticket-service/ticket/query?fromStation=BJP&toStation=HZH&departureDate=2024-05-15
  219. @Override
  220. public TicketPageQueryRespDTO pageListTicketQueryByRedis(TicketPageQueryReqDTO requestParam) {
  221. StringRedisTemplate stringRedisTemplate = (StringRedisTemplate) distributedCache.getInstance();
  222. // 先获取 index12306-ticket-service:region_train_station_mapping 中的数据
  223. // 得到出发站和目的站的名字
  224. List<Object> stationDetails = stringRedisTemplate.opsForHash()
  225. .multiGet(REGION_TRAIN_STATION_MAPPING, Lists.newArrayList(requestParam.getFromStation(), requestParam.getToStation()));
  226. // index12306-ticket-service:region_train_station:%s_%s
  227. // 拼接出key index12306-ticket-service:region_train_station:北京_杭州
  228. String buildRegionTrainStationHashKey = String.format(REGION_TRAIN_STATION, stationDetails.get(0), stationDetails.get(1));
  229. // 从redis中 取出key存储的value值 对应一个map结果
  230. Map<Object, Object> regionTrainStationAllMap = stringRedisTemplate.opsForHash().entries(buildRegionTrainStationHashKey);
  231. // 遍历其中每个元素 转化为多个TicketListDTO对象组成的list
  232. List<TicketListDTO> seatResults = regionTrainStationAllMap.values().stream().map(
  233. each -> JSON.parseObject(each.toString(), TicketListDTO.class)).toList();
  234. //使用普通的方式来处理的逻辑
  235. // List<TicketListDTO> newSeatResults = new ArrayList<>();
  236. // Collection<Object> values = regionTrainStationAllMap.values();
  237. // values.forEach((Object each) -> {
  238. // TicketListDTO ticketListDTO = JSON.parseObject(each.toString(), TicketListDTO.class);
  239. // newSeatResults.add(ticketListDTO);
  240. // });
  241. // 按照出发时间排序
  242. seatResults = seatResults.stream().sorted(new TimeStringComparator()).toList();
  243. for (TicketListDTO each : seatResults) {
  244. // index12306-ticket-service:train_station_price:%s_%s_%s
  245. // 拼接成key index12306-ticket-service:train_station_price:1_北京南_杭州东
  246. String trainStationPriceStr = distributedCache.safeGet(
  247. String.format(TRAIN_STATION_PRICE, each.getTrainId(), each.getDeparture(), each.getArrival()),
  248. String.class,
  249. null,
  250. ADVANCE_TICKET_DAY,
  251. TimeUnit.DAYS
  252. );
  253. // 返回结果是由 TrainStationPriceDO对象组成的list 所转化的json数据
  254. List<TrainStationPriceDO> trainStationPriceDOList = JSON.parseArray(trainStationPriceStr, TrainStationPriceDO.class);
  255. List<SeatClassDTO> seatClassList = new ArrayList<>();
  256. // 遍历每一个TrainStationPriceDO
  257. trainStationPriceDOList.forEach(item -> {
  258. String seatType = String.valueOf(item.getSeatType());
  259. // 拼接成key index12306-ticket-service:train_station_remaining_ticket:1_北京南_杭州东
  260. String keySuffix = StrUtil.join("_", each.getTrainId(), item.getDeparture(), item.getArrival());
  261. // 获取每个席别对应的票数
  262. Object quantityObj = stringRedisTemplate.opsForHash().get(TRAIN_STATION_REMAINING_TICKET + keySuffix, seatType);
  263. int quantity = Optional.ofNullable(quantityObj).map(Object::toString).map(Integer::parseInt).get();
  264. seatClassList.add(new SeatClassDTO(item.getSeatType(), quantity,
  265. new BigDecimal(item.getPrice()).divide(new BigDecimal("100"), 1, RoundingMode.HALF_UP),
  266. false));
  267. });
  268. each.setSeatClassList(seatClassList);
  269. }
  270. // 组装数据
  271. return TicketPageQueryRespDTO.builder()
  272. .trainList(seatResults)
  273. .departureStationList(buildDepartureStationList(seatResults))
  274. .arrivalStationList(buildArrivalStationList(seatResults))
  275. .trainBrandList(buildTrainBrandList(seatResults))
  276. .seatClassTypeList(buildSeatClassList(seatResults))
  277. .build();
  278. }
  279. @Override
  280. public TicketPurchaseRespDTO purchaseTicketsV2(PurchaseTicketReqDTO requestParam) {
  281. return executePurchaseTickets(requestParam);
  282. }
  283. public TicketPurchaseRespDTO executePurchaseTickets(PurchaseTicketReqDTO requestParam) {
  284. List<TicketOrderDetailRespDTO> ticketOrderDetailResults = new ArrayList<>();
  285. String trainId = requestParam.getTrainId();
  286. // 节假日高并发购票Redis能扛得住么?详情查看:https://nageoffer.com/12306/question
  287. TrainDO trainDO = trainMapper.selectById(trainId);
  288. List<TrainPurchaseTicketRespDTO> trainPurchaseTicketResults = trainSeatTypeSelector.select(trainDO.getTrainType(), requestParam);
  289. List<TicketDO> ticketDOList = trainPurchaseTicketResults.stream()
  290. .map(each -> TicketDO.builder()
  291. .username(UserContext.getUsername())
  292. .trainId(Long.parseLong(requestParam.getTrainId()))
  293. .carriageNumber(each.getCarriageNumber())
  294. .seatNumber(each.getSeatNumber())
  295. .passengerId(each.getPassengerId())
  296. .ticketStatus(0) //未支付状态
  297. .build())
  298. .toList();
  299. saveBatch(ticketDOList);
  300. Result<String> ticketOrderResult;
  301. try {
  302. List<TicketOrderItemCreateRemoteReqDTO> orderItemCreateRemoteReqDTOList = new ArrayList<>();
  303. trainPurchaseTicketResults.forEach(each -> {
  304. TicketOrderItemCreateRemoteReqDTO orderItemCreateRemoteReqDTO = TicketOrderItemCreateRemoteReqDTO.builder()
  305. .amount(each.getAmount())
  306. .carriageNumber(each.getCarriageNumber())
  307. .seatNumber(each.getSeatNumber())
  308. .idCard(each.getIdCard())
  309. .idType(each.getIdType())
  310. .phone(each.getPhone())
  311. .seatType(each.getSeatType())
  312. .ticketType(each.getUserType())
  313. .realName(each.getRealName())
  314. .build();
  315. TicketOrderDetailRespDTO ticketOrderDetailRespDTO = TicketOrderDetailRespDTO.builder()
  316. .amount(each.getAmount())
  317. .carriageNumber(each.getCarriageNumber())
  318. .seatNumber(each.getSeatNumber())
  319. .idCard(each.getIdCard())
  320. .idType(each.getIdType())
  321. .seatType(each.getSeatType())
  322. .ticketType(each.getUserType())
  323. .realName(each.getRealName())
  324. .build();
  325. orderItemCreateRemoteReqDTOList.add(orderItemCreateRemoteReqDTO);
  326. ticketOrderDetailResults.add(ticketOrderDetailRespDTO);
  327. });
  328. LambdaQueryWrapper<TrainStationRelationDO> queryWrapper = Wrappers.lambdaQuery(TrainStationRelationDO.class)
  329. .eq(TrainStationRelationDO::getTrainId, trainId)
  330. .eq(TrainStationRelationDO::getDeparture, requestParam.getDeparture())
  331. .eq(TrainStationRelationDO::getArrival, requestParam.getArrival());
  332. TrainStationRelationDO trainStationRelationDO = trainStationRelationMapper.selectOne(queryWrapper);
  333. TicketOrderCreateRemoteReqDTO orderCreateRemoteReqDTO = TicketOrderCreateRemoteReqDTO.builder()
  334. .departure(requestParam.getDeparture())
  335. .arrival(requestParam.getArrival())
  336. .orderTime(new Date())
  337. .source(0) //购票方式 互联网购票是0
  338. .trainNumber(trainDO.getTrainNumber())
  339. .departureTime(trainStationRelationDO.getDepartureTime())
  340. .arrivalTime(trainStationRelationDO.getArrivalTime())
  341. .ridingDate(trainStationRelationDO.getDepartureTime())
  342. .userId(UserContext.getUserId())
  343. .username(UserContext.getUsername())
  344. .trainId(Long.parseLong(requestParam.getTrainId()))
  345. .ticketOrderItems(orderItemCreateRemoteReqDTOList)
  346. .build();
  347. ticketOrderResult = ticketOrderRemoteService.createTicketOrder(orderCreateRemoteReqDTO);
  348. if (!ticketOrderResult.isSuccess() || StrUtil.isBlank(ticketOrderResult.getData())) {
  349. log.error("订单服务调用失败,返回结果:{}", ticketOrderResult.getMessage());
  350. throw new ServiceException("订单服务调用失败");
  351. }
  352. } catch (Throwable ex) {
  353. log.error("远程调用订单服务创建错误,请求参数:{}", JSON.toJSONString(requestParam), ex);
  354. throw ex;
  355. }
  356. return new TicketPurchaseRespDTO(ticketOrderResult.getData(), ticketOrderDetailResults);
  357. }
  358. private List<String> buildDepartureStationList(List<TicketListDTO> seatResults) {
  359. return seatResults.stream().map(TicketListDTO::getDeparture).distinct().collect(Collectors.toList());
  360. }
  361. private List<String> buildArrivalStationList(List<TicketListDTO> seatResults) {
  362. return seatResults.stream().map(TicketListDTO::getArrival).distinct().collect(Collectors.toList());
  363. }
  364. private List<Integer> buildSeatClassList(List<TicketListDTO> seatResults) {
  365. Set<Integer> resultSeatClassList = new HashSet<>();
  366. for (TicketListDTO each : seatResults) {
  367. for (SeatClassDTO item : each.getSeatClassList()) {
  368. resultSeatClassList.add(item.getType());
  369. }
  370. }
  371. return resultSeatClassList.stream().toList();
  372. }
  373. private List<Integer> buildTrainBrandList(List<TicketListDTO> seatResults) {
  374. Set<Integer> trainBrandSet = new HashSet<>();
  375. for (TicketListDTO each : seatResults) {
  376. if (StrUtil.isNotBlank(each.getTrainBrand())) {
  377. trainBrandSet.addAll(StrUtil.split(each.getTrainBrand(), ",").stream().map(Integer::parseInt).toList());
  378. }
  379. }
  380. return trainBrandSet.stream().toList();
  381. }
  382. }