xp-robotaxi-account-boot/src/main/java/com/xiaopeng/account/config/MiniprogramConfigurer.java
@@ -10,7 +10,7 @@ import javax.annotation.Resource; @Slf4j @Configuration //@Configuration public class MiniprogramConfigurer extends WebMvcConfigurerAdapter { @Resource xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/XpOpenCityClientFallbackFactory.java
@@ -35,6 +35,12 @@ log.error("获取开通城市失败"); return R.fail("获取开通城市失败"); } @Override public R<XpOpenCity> getXpOpenCityById(Long id) { log.error("获取开通城市失败"); return R.fail("获取开通城市失败"); } }; } } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/map/XpMapClient.java
@@ -57,6 +57,6 @@ /** * 获取指定城市的天气 */ @GetMapping("/logan/inner/weatherInfo") R<WeatherDTO> wether(@RequestParam String cityCode); @PostMapping("/logan/inner/weatherInfo") R<WeatherDTO> wether(@RequestParam("cityCode") String cityCode); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpOpenCityClient.java
@@ -31,4 +31,13 @@ R<XpOpenCity> getXpOpenCity(@RequestParam("provinceCode") String provinceCode, @RequestParam("cityCode") String cityCode, @RequestParam("districtCode") String districtCode); /** * 根据id查询开通城市 * @param id * @return */ @PostMapping("/logan/inner/v1/openCity/getXpOpenCityById") R<XpOpenCity> getXpOpenCityById(@RequestParam("id") Long id); } xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrder.java
@@ -127,6 +127,9 @@ @ApiModelProperty(value = "预付金额") private BigDecimal prepayMoney; @ApiModelProperty(value = "关闭订单的时候不能为空 是否豁免(0=否,1=是)") private Boolean isFree; @ApiModelProperty(value = "起步里程") private Double startMileage; xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrderReassign.java
@@ -1,14 +1,15 @@ package com.xiaopeng.api.model.order; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import com.xiaopeng.common.core.web.domain.BaseModel; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import com.fasterxml.jackson.annotation.JsonFormat; import javax.validation.constraints.NotNull; import java.time.LocalDateTime; /** @@ -33,7 +34,9 @@ private Long id; @ApiModelProperty(value = "订单id") @NotNull(message = "订单id不能为空") private Long orderId; @TableField(exist = false) @ApiModelProperty(value = "订单号") private String orderNumber; @@ -49,6 +52,7 @@ private Long oldVehicleId; @ApiModelProperty(value = "新车辆id") @NotNull(message = "新车辆id不能为空") private Long newVehicleId; @ApiModelProperty(value = "原车队id") xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/vehicleConvoy/XpVehicle.java
@@ -136,4 +136,14 @@ @TableField(exist = false) private String vehicleModelName; @ApiModelProperty(value = "在订单改派里展示-预估到达时间") @TableField(exist = false) private String arrivalTime; @TableField(exist = false) @ApiModelProperty(value = "在订单改派里展示-预估到达时间秒") private Integer arrivalTimeSecond; @ApiModelProperty(value = "在订单改派里展示-预估到达距离米") @TableField(exist = false) private Integer arrivalDistance; } xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/config/MiniprogramConfigurer.java
@@ -10,7 +10,7 @@ import javax.annotation.Resource; @Slf4j @Configuration //@Configuration public class MiniprogramConfigurer extends WebMvcConfigurerAdapter { @Resource xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/controller/ActiveOrderController.java
@@ -35,7 +35,7 @@ @Slf4j @RestController @RequestMapping("") @Api(tags = "费用管理") @Api(tags = "行程中管理") public class ActiveOrderController { @Resource xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/utils/XpPricingUtil.java
@@ -7,7 +7,9 @@ import com.xiaopeng.api.dto.WeatherDTO; import com.xiaopeng.api.dto.order.GetOrderNumDto; import com.xiaopeng.api.feignClient.map.XpMapClient; import com.xiaopeng.api.feignClient.operation.XpOpenCityClient; import com.xiaopeng.api.feignClient.order.XpOrderClient; import com.xiaopeng.api.model.operation.XpOpenCity; import com.xiaopeng.api.vo.order.XpPricingCardVo; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.redis.service.RedisService; @@ -69,6 +71,11 @@ // @Resource XpMapClient xpMapClient; @Resource private XpOpenCityClient openCityClient; /** * 计算一口价 */ @@ -106,20 +113,25 @@ // 当前费率+(费率*上升百分比) priceRate = new BigDecimal(priceRate).multiply(divide).add(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); } List<WeatherDTO.Lives> lives = xpMapClient.wether(openCityId.toString()).getData().getLives(); if(lives!=null && !lives.isEmpty()){ String w = lives.get(0).getWeather(); Set<String> weather = jsonObject.getJSONObject("weather").keySet(); for (String k : weather) { if(w.contains(k)){ double floatRate = jsonObject.getDouble(k); priceRate = new BigDecimal(priceRate).add(new BigDecimal(floatRate)).doubleValue(); break; JSONObject jsonObject1 = jsonObject.getJSONObject("weather"); if(null != jsonObject1){ XpOpenCity openCity = openCityClient.getXpOpenCityById(openCityId).getData(); WeatherDTO data = xpMapClient.wether(openCity.getCityCode()).getData(); List<WeatherDTO.Lives> lives = data.getLives(); if(lives!=null && !lives.isEmpty()){ String w = lives.get(0).getWeather(); Set<String> weather = jsonObject1.keySet(); for (String k : weather) { if(w.contains(k)){ double floatRate = jsonObject.getDouble(k); priceRate = new BigDecimal(priceRate).add(new BigDecimal(floatRate)).doubleValue(); break; } } } } // 冷却时间 Integer time = getOrderNum(jsonObject, 6); // 触发调价了 xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java
@@ -205,21 +205,23 @@ String key; @ApiOperation(value = "获取天气信息", tags = {"内部-调价"}) @GetMapping("/logan/inner/weatherInfo") public R<WeatherDTO> weather(@RequestParam String city) throws IOException { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpGet httpGet = new HttpGet(String.format(WEATHER_URL, key, city)); try (CloseableHttpResponse response = httpClient.execute(httpGet)) { HttpEntity entity = response.getEntity(); if (entity != null) { String resp = EntityUtils.toString(entity, StandardCharsets.UTF_8); System.out.println(resp); return R.ok(om.readValue(resp, WeatherDTO.class)); } return R.fail("获取天气信息失败"); @PostMapping("/logan/inner/weatherInfo") public R<WeatherDTO> wether(@RequestParam("cityCode") String cityCode) { try{ CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(String.format(WEATHER_URL, key, cityCode)); CloseableHttpResponse response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); if (entity != null) { String resp = EntityUtils.toString(entity, StandardCharsets.UTF_8); log.info("天气预报查询结果:{}", resp); return R.ok(om.readValue(resp, WeatherDTO.class)); } return R.fail("获取天气信息失败"); }catch (Exception e){ e.printStackTrace(); } return R.fail("获取天气信息失败"); } } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/config/MiniprogramConfigurer.java
@@ -10,7 +10,7 @@ import javax.annotation.Resource; @Slf4j @Configuration //@Configuration public class MiniprogramConfigurer extends WebMvcConfigurerAdapter { @Resource xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpOpenCityController.java
@@ -153,4 +153,16 @@ XpOpenCity xpOpenCity = xpOpenCityService.getXpOpenCity(provinceCode, cityCode, districtCode); return R.ok(xpOpenCity); } /** * 根据id查询开通城市 * @param id * @return */ @PostMapping("/logan/inner/v1/openCity/getXpOpenCityById") public R<XpOpenCity> getXpOpenCityById(@RequestParam("id") Long id){ XpOpenCity xpOpenCity = xpOpenCityService.getById(id); return R.ok(xpOpenCity); } } xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpTargetedServiceController.java
@@ -116,7 +116,7 @@ /** * 批量删除 */ @GetMapping("/api/v1/whitelist/deleteByIds") @GetMapping("/api/v1/targetedService/deleteByIds") @ApiOperation(value = "定向服务-批量删除", tags = {"管理后台-定向服务批量删除"}) public R deleteByIds(String ids) { SysUser sysUser = tokenService.getLoginUser().getSysUser(); xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/task/TaskUtil.java
@@ -24,10 +24,8 @@ @Resource private XpPointService xpPointService; @Resource private IXpElectronicFenceAreaService xpElectronicFenceAreaService; @Resource private IXpElectronicFenceService xpElectronicFenceService; // 每隔1分钟执行一次 如果运营区域不处于启用状态 将关联的点位状态修改为已停用 @Scheduled(fixedRate = 60 * 1000) xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderController.java
@@ -291,7 +291,7 @@ @ApiOperation(value = "取消/关闭订单", tags = {"管理后台-交易管理-订单管理"}) @PostMapping("/api/v1/order/cancelAndCloseById") public R<?> cancelAndCloseById(@Validated @RequestBody XpOrderOperateDTO dto) { xpOrderService.cancelOrCloseOrder(dto.getOrderId(), dto.getType()); xpOrderService.cancelOrCloseOrder(dto.getOrderId(), dto.getType(),dto.getIsFree()); return R.ok(); } @@ -301,7 +301,7 @@ * @param dto 改派请求参数 * @return 操作结果 */ @ApiOperation(value = "改派订单", tags = {"管理后台-交易管理-订单管理"}, notes = "车辆列表在vehicleConvoy服务") @ApiOperation(value = "改派订单", tags = {"管理后台-交易管理-订单管理"}, notes = "车辆列表在 vehicleConvoy.availableList 服务") @PostMapping("/api/v1/order/reassignById") public R<?> reassignById(@Validated @RequestBody XpOrderReassignDTO dto) { xpOrderService.reassignOrder( xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpOrderReassignController.java
@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.xiaopeng.api.model.order.XpOrderReassign; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.OrderStatusEnum; import com.xiaopeng.order.service.IXpOrderReassignService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -17,7 +16,6 @@ import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.List; import java.util.concurrent.TimeUnit; /** * <p> xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/model/dto/XpOrderOperateDTO.java
@@ -24,4 +24,9 @@ @NotNull(message = "操作类型不能为空") private Integer type; @ApiModelProperty(value = "关闭订单的时候不能为空 是否豁免费用(0=否,1=是)") private Boolean isFree; } xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/IXpOrderService.java
@@ -88,7 +88,7 @@ * @param orderId 订单ID * @param type 操作类型:1=取消订单,2=关闭订单 */ void cancelOrCloseOrder(Long orderId, Integer type); void cancelOrCloseOrder(Long orderId, Integer type,Boolean isFree); /** * 改派订单 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -547,14 +547,14 @@ @Override @Transactional @ShardingSphereTransactionType(TransactionType.BASE) public void cancelOrCloseOrder(Long orderId, Integer type) { public void cancelOrCloseOrder(Long orderId, Integer type,Boolean isFree) { // 1. 校验订单是否存在 XpOrder order = this.getById(orderId); if (Objects.isNull(order)) { throw new ServiceException("订单不存在"); } // 2. 校验操作类型 // 2. 校验操作类型 操作类型:1=取消订单,2=关闭订单 if (type != 1 && type != 2) { throw new ServiceException("操作类型错误,type只能为1或2"); } @@ -568,6 +568,9 @@ throw new ServiceException("当前订单状态不允许取消,只有待接单、待出发、接驾中状态的订单可以取消", I18nKeyConstant.ORDER_CANCEL_FAILED); } } else { if(isFree == null){ throw new ServiceException("是否豁免费用不能为空", I18nKeyConstant.ORDER_CLOSE_FAILED); } // 关闭订单:0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中 状态可以关闭 if (currentStatus == 7 || currentStatus == 8 || currentStatus == 9 || currentStatus == 10) { throw new ServiceException("当前订单状态不允许关闭", I18nKeyConstant.ORDER_CLOSE_FAILED); @@ -581,6 +584,9 @@ } else { // 关闭订单 closeOrder(order); if(isFree){ this.setFree(order.getId()); } } } @@ -2073,15 +2079,25 @@ this.endTrip(xpOrder.getId(),appUserId.toString()); //将支付金额修改成0 并将状态修改成 订单状态9 setFree(xpOrder.getId()); return R.ok(); } /** * 豁免 */ public void setFree(Long id){ //将支付金额修改成0 并将状态修改成 订单状态9 XpOrder xpOrder1 = new XpOrder(); xpOrder1.setId(xpOrder.getId()); xpOrder1.setId(id); xpOrder1.setIsFree( true);//豁免 xpOrder1.setPayMoney(BigDecimal.ZERO); xpOrder1.setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode()); xpOrder1.setUpdateTime(LocalDateTime.now()); baseMapper.updateById(xpOrder1); redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), xpOrder1.getStatus(), 24L, TimeUnit.HOURS); redisService.setCacheObject("ORDER_STATUS:" + id, xpOrder1.getStatus(), 24L, TimeUnit.HOURS); return R.ok(); } xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/webSocket/handler/WebSocketTextFrameHandler.java
@@ -155,6 +155,14 @@ log.info("收到用户 {} 的业务消息: {}", appUserId, messageObj.toJSONString()); businessMsgHandlers.get(messageObj.getString("type")).handle(appUserId, messageObj.getString("message")); //判断处理用户实时位置 if ("location".equals(messageObj.getString("type"))) { log.info("收到用户 {} 的实时位置消息: {}", appUserId, messageObj.toJSONString()); Double latitude = messageObj.getDouble("latitude"); Double longitude = messageObj.getDouble("longitude"); String timestamp = messageObj.getString("timestamp"); } // 回复消息 JSONObject response = new JSONObject(); xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -10,16 +10,16 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.ImmutableMap; import com.xiaopeng.api.dto.account.UcUserInfo; import com.xiaopeng.api.dto.pushMessage.SendMessageDTO; import com.xiaopeng.api.dto.map.OrderRouteAndFareDto; import com.xiaopeng.api.dto.operation.LonLatDto; import com.xiaopeng.api.dto.vehicleConvoy.ServiceVehicleListDto; import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto; import com.xiaopeng.api.feignClient.account.UserResourcesClient; import com.xiaopeng.api.feignClient.automaticPilot.XpuVinClient; import com.xiaopeng.api.feignClient.map.AdcFencePushClient; import com.xiaopeng.api.feignClient.map.XpMapClient; import com.xiaopeng.api.feignClient.operation.XpElectronicClient; import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient; import com.xiaopeng.api.feignClient.order.XpOrderClient; import com.xiaopeng.api.feignClient.order.XpTestOrderClient; import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient; @@ -29,31 +29,30 @@ import com.xiaopeng.api.model.operation.XpElectronicFenceArea; import com.xiaopeng.api.model.order.XpOrder; import com.xiaopeng.api.model.order.XpTestOrder; import com.xiaopeng.api.model.vehicleConvoy.*; import com.xiaopeng.api.model.vehicleConvoy.XpFleetOperations; import com.xiaopeng.api.model.vehicleConvoy.XpFleetVehicle; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.model.vehicleConvoy.XpVehicleAnnualRecord; import com.xiaopeng.api.vo.automaticPilot.VehiclePosition; import com.xiaopeng.api.vo.operation.ElectronicFenceDetailVo; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.api.vo.vehicleConvoy.*; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.OrderStatusEnum; import com.xiaopeng.common.core.enums.PushMessageTypeEnum; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.utils.DateUtils; import com.xiaopeng.common.core.utils.GeodesyUtil; import com.xiaopeng.common.core.web.page.PageInfo; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.evi.oss.service.AliOssService; import com.xiaopeng.vehicleConvoy.constant.I18nKeyConstant; import com.xiaopeng.vehicleConvoy.mapper.XpFleetMapper; import com.xiaopeng.vehicleConvoy.mapper.XpFleetOperationsMapper; import com.xiaopeng.vehicleConvoy.mapper.XpVehicleMapper; import com.xiaopeng.vehicleConvoy.model.dto.*; import com.xiaopeng.vehicleConvoy.model.importExcel.XpVehicleImportExcel; import com.xiaopeng.vehicleConvoy.model.query.*; import com.xiaopeng.vehicleConvoy.model.vo.XpVehicleVO; import com.xiaopeng.vehicleConvoy.service.IXpFleetService; import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService; import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService; import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService; import com.xiaopeng.vehicleConvoy.service.IXpVehicleService; import com.xiaopeng.vehicleConvoy.util.VehicleControlUtil; import lombok.extern.slf4j.Slf4j; @@ -63,7 +62,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.geo.GeoJsonPoint; import org.springframework.data.mongodb.core.query.Criteria; @@ -74,12 +72,14 @@ import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; import java.util.stream.Collectors; import java.util.regex.Pattern; import java.util.stream.Collectors; /** * <p> @@ -117,6 +117,8 @@ private RedisService redisService; @Autowired private MongoTemplate mongoTemplate; @Resource private XpMapClient xpMapClient; @Autowired private AliOssService aliOssService; @Autowired @@ -153,10 +155,19 @@ return super.listByIds(ids); } /** * * @param orderId * @param orderType 订单类型(1=用户单,2=测试单) * @return */ @Override public List<XpVehicle> listAvailableVehicles(Long orderId, Integer orderType) { // 1. 通过订单ID查询订单信息,获取区域ID Long areaId = null; Double longitude =null;//经度 Double latitude =null;//纬度 if (null == orderType || 1 == orderType) { R<XpOrder> orderResult = xpOrderClient.queryOrderById(orderId); if (orderResult == null || orderResult.getData() == null) { @@ -166,9 +177,13 @@ XpOrder order = orderResult.getData(); areaId = order.getXpElectronicFenceAreaId(); longitude = order.getStartLon(); latitude = order.getStartLat(); } else { XpTestOrder testOrder = xpTestOrderClient.queryOrderById(orderId).getData(); areaId = testOrder.getXpElectronicFenceAreaId(); longitude = testOrder.getStartLon(); latitude = testOrder.getStartLat(); } if (areaId == null) { @@ -198,8 +213,69 @@ // 排序:按电量降序、入库时间降序 wrapper.orderByDesc(XpVehicle::getCurrentElectricity) .orderByDesc(XpVehicle::getWarehousingTime); List<XpVehicle> list = this.list(wrapper); //获取车的位置 和订单的位置 并计算 距离 和 时间 if(!list.isEmpty()){ for (XpVehicle xpVehicle : list) { return this.list(wrapper); VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class); if(vehiclePosition == null){ continue; } OrderRouteAndFareDto dto = new OrderRouteAndFareDto(); dto.setOrderId(orderId); LonLatDto origin = new LonLatDto(); origin.setLongitude(longitude); origin.setLatitude(latitude); dto.setOrigin(origin); LonLatDto destination = new LonLatDto(); destination.setLongitude(vehiclePosition.getPoint().getX()); destination.setLatitude(vehiclePosition.getPoint().getY()); dto.setDestination(destination); dto.setRouteType(1); // dto.setVehicleId(xpVehicle.getId()); R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto); if (200 != routeVoR.getCode()) { throw new RuntimeException("获取订单线路失败"); } if(routeVoR.getData() != null){ xpVehicle.setArrivalDistance(routeVoR.getData().getDistance()); xpVehicle.setArrivalTimeSecond(routeVoR.getData().getDuration()); if(routeVoR.getData().getDuration() != null){ BigDecimal time = new BigDecimal(routeVoR.getData().getDuration()); if(time.compareTo(new BigDecimal("60"))<0){ //秒 xpVehicle.setArrivalTime(time.toPlainString()+"秒"); }else if(time.compareTo(new BigDecimal("60"))>0 && time.compareTo(new BigDecimal("3600"))<0){//分 BigDecimal min = time.divide(new BigDecimal("60"), 0, RoundingMode.HALF_UP); xpVehicle.setArrivalTime(min.toPlainString()+"分钟"); }else if(time.compareTo(new BigDecimal("3600"))>0){//小时 // 计算小时和分钟 long totalSeconds = time.longValue(); long hours = totalSeconds / 3600; long minutes = (totalSeconds % 3600) / 60; StringBuilder timeStr = new StringBuilder(); if (hours > 0) { timeStr.append(hours).append("小时"); } if (minutes > 0 || hours == 0) { timeStr.append(minutes).append("分钟"); } xpVehicle.setArrivalTime(timeStr.toString()); } } } } // 按预计到达时间(秒)升序排序 list.sort(Comparator.comparing(XpVehicle::getArrivalTimeSecond, Comparator.nullsLast(Comparator.naturalOrder()))); } return list; } @Override