Merge remote-tracking branch 'origin/master'
| | |
| | | public R<String> pushOrderRoute(PushOrderRouteDTO dto) { |
| | | return R.fail("通过车辆实时定位推送订单轨迹失败,"+cause.getMessage()); |
| | | } |
| | | |
| | | @Override |
| | | public R<String> sendOpenTrunk(SendMessageDTO dto) { |
| | | return R.fail("通过发送是否开启倒计时失败,"+cause.getMessage()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | */ |
| | | @PostMapping("/inner/v1/order/pushOrderRoute") |
| | | R<String> pushOrderRoute(@RequestBody PushOrderRouteDTO dto); |
| | | /** |
| | | * 发送是否开启倒计时 |
| | | * |
| | | * @param dto 消息实体 |
| | | * @return 发送是否开启倒计时 |
| | | */ |
| | | @PostMapping("/inner/websocket/order/sendOpenTrunk") |
| | | R<String> sendOpenTrunk(@RequestBody SendMessageDTO dto); |
| | | |
| | | } |
| | |
| | | |
| | | @ApiModelProperty(value = "type=1 普通时段 type=2 夜间行驶时段 3高峰时段 4节假日时段") |
| | | private Integer type; |
| | | @ApiModelProperty(value = "1=起步价 2=里程费") |
| | | @ApiModelProperty(value = "1=起步价 2=里程费 3时长 4远途") |
| | | private Integer detailType; |
| | | |
| | | @ApiModelProperty(value = "时段") |
| | |
| | | |
| | | ORDER_STATUS("ORDER_STATUS"), |
| | | VEHICLE_LOCATION("VEHICLE_LOCATION"), |
| | | ORDER_ROUTE("ORDER_ROUTE"); |
| | | ORDER_ROUTE("ORDER_ROUTE"), |
| | | OPEN_TRUNK("OPEN_TRUNK"); |
| | | |
| | | @Getter |
| | | private String desc; |
| | |
| | | import javax.annotation.Resource; |
| | | import java.awt.geom.Point2D; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | * @return |
| | | */ |
| | | private org.locationtech.jts.geom.Point calculateCentroid(Coordinate[] coordinates) { |
| | | GeometryFactory factory = new GeometryFactory(); |
| | | // 创建线性环 (LinearRing) |
| | | LinearRing ring = factory.createLinearRing(coordinates); |
| | | // 创建多边形 (Polygon) |
| | | Polygon polygon = factory.createPolygon(ring); |
| | | // 计算质心 (Centroid) |
| | | org.locationtech.jts.geom.Point centroid = polygon.getCentroid(); |
| | | // 1. 判空校验 |
| | | if (coordinates == null || coordinates.length == 0) { |
| | | throw new ServiceException("坐标数组不能为空"); |
| | | } |
| | | |
| | | // 2. 过滤掉 null 坐标点 |
| | | Coordinate[] validCoords = Arrays.stream(coordinates) |
| | | .filter(Objects::nonNull) |
| | | .toArray(Coordinate[]::new); |
| | | |
| | | // 3. LinearRing 至少需要 4 个点(首尾相同),且必须闭合 |
| | | if (validCoords.length < 4) { |
| | | throw new ServiceException("有效坐标点不足,至少需要4个点"); |
| | | } |
| | | |
| | | // 4. 确保首尾坐标相同(闭合) |
| | | Coordinate first = validCoords[0]; |
| | | Coordinate last = validCoords[validCoords.length - 1]; |
| | | if (!first.equals2D(last)) { |
| | | // 自动补上闭合点 |
| | | validCoords = Arrays.copyOf(validCoords, validCoords.length + 1); |
| | | validCoords[validCoords.length - 1] = new Coordinate(first.x, first.y); |
| | | } |
| | | |
| | | GeometryFactory factory = new GeometryFactory(); |
| | | LinearRing ring = factory.createLinearRing(validCoords); |
| | | Polygon polygon = factory.createPolygon(ring); |
| | | org.locationtech.jts.geom.Point centroid = polygon.getCentroid(); |
| | | System.out.println("中心点经度: " + centroid.getX()); |
| | | System.out.println("中心点纬度: " + centroid.getY()); |
| | | return centroid; |
| | |
| | | if (CollUtil.isNotEmpty(lonAndLat)) { |
| | | query.setPointLon(lonAndLat.get(0)); |
| | | query.setPointLat(lonAndLat.get(1)); |
| | | query.setPointLonAndLat(null); |
| | | } |
| | | query.setPointLonAndLat(null); |
| | | } |
| | | List<XpPoint> list = this.baseMapper.pageList(pageInfo,query); |
| | | pageInfo.setRecords(list); |
| | |
| | | break; |
| | | case 7: |
| | | // 查询自动结束行程时间 |
| | | Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData(); |
| | | // 添加自动结束行程定时任务job |
| | | Map<String, ? extends Object> endTripJobMaps = |
| | | new ImmutableMap.Builder<String, Long>(). |
| | | put("id", xpOrder.getId()) |
| | | .build(); |
| | | QuartzManager.addJob( |
| | | EndTripJob.class, |
| | | (EndTripJob.name + xpOrder.getId()).toUpperCase(), |
| | | TimeJobType.END_TRIP, |
| | | DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)), |
| | | endTripJobMaps |
| | | ); |
| | | if(xpOrder.getOpenTrunk() != 1){ |
| | | Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData(); |
| | | // 添加自动结束行程定时任务job |
| | | Map<String, ? extends Object> endTripJobMaps = |
| | | new ImmutableMap.Builder<String, Long>(). |
| | | put("id", xpOrder.getId()) |
| | | .build(); |
| | | QuartzManager.addJob( |
| | | EndTripJob.class, |
| | | (EndTripJob.name + xpOrder.getId()).toUpperCase(), |
| | | TimeJobType.END_TRIP, |
| | | DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)), |
| | | endTripJobMaps |
| | | ); |
| | | // 推送倒计时消息 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId", xpOrder.getId().toString()); |
| | | content.put("isOpen", 1); |
| | | params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc()); |
| | | params.put("content", JSONObject.toJSONString(content)); |
| | | params.put("timestamp", new Date().getTime() + ""); |
| | | String message = JSONObject.toJSONString(params); |
| | | SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | sendMessageDTO.setMessage(message); |
| | | sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId())); |
| | | xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | } |
| | | break; |
| | | } |
| | | xpOrder.setAppUserId(null); |
| | |
| | | |
| | | TaxiPricingDemoService.PricingConfig config = new TaxiPricingDemoService.PricingConfig(); |
| | | JSONArray startingFareJsonArray = JSONArray.parseArray(pricing.getStartingFareJson()); |
| | | if (pricing.getPricingType() == 1) { |
| | | JSONObject basicPricingJson = JSONObject.parseObject(pricing.getBasicPricingJson()); |
| | | config.peaks.add(new TaxiPricingDemoService.PricingRule("高峰期", basicPricingJson.getString("num21").split(" - ")[0], basicPricingJson.getString("num21").split(" - ")[1], Double.parseDouble(basicPricingJson.getString("num24")), Double.parseDouble(basicPricingJson.getString("num25")), Double.parseDouble(basicPricingJson.getString("num26")), Double.parseDouble(basicPricingJson.getString("num27")), Double.parseDouble(basicPricingJson.getString("num28")))); |
| | | config.peaks.add(new TaxiPricingDemoService.PricingRule("高峰期", basicPricingJson.getString("num22").split(" - ")[0], basicPricingJson.getString("num22").split(" - ")[1], Double.parseDouble(basicPricingJson.getString("num24")), Double.parseDouble(basicPricingJson.getString("num25")), Double.parseDouble(basicPricingJson.getString("num26")), Double.parseDouble(basicPricingJson.getString("num27")), Double.parseDouble(basicPricingJson.getString("num28")))); |
| | | config.night = new TaxiPricingDemoService.PricingRule("夜间行驶", basicPricingJson.getString("num14").split(" - ")[0], basicPricingJson.getString("num14").split(" - ")[1], Double.parseDouble(basicPricingJson.getString("num16")), Double.parseDouble(basicPricingJson.getString("num17")), Double.parseDouble(basicPricingJson.getString("num18")), Double.parseDouble(basicPricingJson.getString("num19")), Double.parseDouble(basicPricingJson.getString("num20"))); |
| | | config.holiday = new TaxiPricingDemoService.PricingRule("节假日", "00:00", "23:59", Double.parseDouble(basicPricingJson.getString("num30")), Double.parseDouble(basicPricingJson.getString("num31")), Double.parseDouble(basicPricingJson.getString("num32")), Double.parseDouble(basicPricingJson.getString("num33")), Double.parseDouble(basicPricingJson.getString("num34"))); |
| | | // --- 远途加价区间配置 (关键修改) --- |
| | | // 1. 超过 num1(12) 不足 num2(20), 加收 num3(1.2) |
| | | config.longSteps.add(new TaxiPricingDemoService.LongRangeStep(Double.parseDouble(basicPricingJson.getString("num6")), Double.parseDouble(basicPricingJson.getString("num7")), Double.parseDouble(basicPricingJson.getString("num8")))); |
| | | // 2. 超过 num4(20) 不足 num5(35), 加收 num6(2.0) |
| | | config.longSteps.add(new TaxiPricingDemoService.LongRangeStep(Double.parseDouble(basicPricingJson.getString("num9")), Double.parseDouble(basicPricingJson.getString("num10")), Double.parseDouble(basicPricingJson.getString("num11")))); |
| | | // 3. 超过 num7(35) 以后, 加收 num8(3.5) -> numEnd 传个极大值 |
| | | config.longSteps.add(new TaxiPricingDemoService.LongRangeStep(Double.parseDouble(basicPricingJson.getString("num12")), 999999, Double.parseDouble(basicPricingJson.getString("num13")))); |
| | | } |
| | | |
| | | LocalDateTime boardingTime = order.getBoardingTime(); |
| | | Date date = DateUtils.localDateTimeToDate(boardingTime); |
| | | |
| | | |
| | | double paramNum4 =0.0; |
| | | double paramNum5 =0.0; |
| | | |
| | | |
| | | for (int i = 0; i < startingFareJsonArray.size(); i++) { |
| | | com.alibaba.fastjson.JSONObject jsonObject = startingFareJsonArray.getJSONObject(i); |
| | | String num1 = jsonObject.getString("num1"); |
| | |
| | | String num6 = jsonObject.getString("num6"); |
| | | String num7 = jsonObject.getString("num7"); |
| | | config.normals.add(new TaxiPricingDemoService.PricingRule("普通时段", num1, num2, Double.parseDouble(num3), Double.parseDouble(num4), Double.parseDouble(num5), Double.parseDouble(num6), Double.parseDouble(num7))); |
| | | // 判断当前是那个时段 |
| | | |
| | | Calendar calendarStart = Calendar.getInstance(); |
| | | calendarStart.setTime(date); |
| | | calendarStart.set(Calendar.HOUR_OF_DAY, Integer.valueOf(jsonObject.getString("num1").split(":")[0])); |
| | | calendarStart.set(Calendar.MINUTE, Integer.valueOf(jsonObject.getString("num1").split(":")[1])); |
| | | |
| | | Calendar calendarEnd = Calendar.getInstance(); |
| | | calendarEnd.setTime(date); |
| | | calendarEnd.set(Calendar.HOUR_OF_DAY, Integer.valueOf(jsonObject.getString("num2").split(":")[0])); |
| | | calendarEnd.set(Calendar.MINUTE, Integer.valueOf(jsonObject.getString("num2").split(":")[1])); |
| | | // 找到符合条件的直接跳出循环 |
| | | if (date.getTime() > calendarStart.getTimeInMillis() && date.getTime() < calendarEnd.getTimeInMillis()) { |
| | | paramNum4 = jsonObject.getDouble("num4"); |
| | | paramNum5 = jsonObject.getDouble("num5"); |
| | | break; |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | if (pricing.getPricingType() == 1) { |
| | | JSONObject basicPricingJson = JSONObject.parseObject(pricing.getBasicPricingJson()); |
| | | config.peaks.add(new TaxiPricingDemoService.PricingRule("高峰期", basicPricingJson.getString("num21").split(" - ")[0], basicPricingJson.getString("num21").split(" - ")[1], Double.parseDouble(basicPricingJson.getString("num23")),paramNum4, paramNum5, Double.parseDouble(basicPricingJson.getString("num24")), Double.parseDouble(basicPricingJson.getString("num25")))); |
| | | config.peaks.add(new TaxiPricingDemoService.PricingRule("高峰期", basicPricingJson.getString("num22").split(" - ")[0], basicPricingJson.getString("num22").split(" - ")[1], Double.parseDouble(basicPricingJson.getString("num23")), paramNum4, paramNum5, Double.parseDouble(basicPricingJson.getString("num24")), Double.parseDouble(basicPricingJson.getString("num25")))); |
| | | config.night = new TaxiPricingDemoService.PricingRule("夜间行驶", basicPricingJson.getString("num14").split(" - ")[0], basicPricingJson.getString("num14").split(" - ")[1], Double.parseDouble(basicPricingJson.getString("num15")), paramNum4, paramNum5, Double.parseDouble(basicPricingJson.getString("num16")), Double.parseDouble(basicPricingJson.getString("num17"))); |
| | | config.holiday = new TaxiPricingDemoService.PricingRule("节假日", "00:00", "23:59", Double.parseDouble(basicPricingJson.getString("num29")), paramNum4, paramNum5, Double.parseDouble(basicPricingJson.getString("num30")), Double.parseDouble(basicPricingJson.getString("num31"))); |
| | | // --- 远途加价区间配置 (关键修改) --- |
| | | // 1. 超过 num1(12) 不足 num2(20), 加收 num3(1.2) |
| | | config.longSteps.add(new TaxiPricingDemoService.LongRangeStep(Double.parseDouble(basicPricingJson.getString("num6")), Double.parseDouble(basicPricingJson.getString("num7")), Double.parseDouble(basicPricingJson.getString("num8")))); |
| | | // 2. 超过 num4(20) 不足 num5(35), 加收 num6(2.0) |
| | | config.longSteps.add(new TaxiPricingDemoService.LongRangeStep(Double.parseDouble(basicPricingJson.getString("num9")), Double.parseDouble(basicPricingJson.getString("num10")), Double.parseDouble(basicPricingJson.getString("num11")))); |
| | | // 3. 超过 num7(35) 以后, 加收 num8(3.5) -> numEnd 传个极大值 |
| | | config.longSteps.add(new TaxiPricingDemoService.LongRangeStep(Double.parseDouble(basicPricingJson.getString("num12")), 999999, Double.parseDouble(basicPricingJson.getString("num13")))); |
| | | } |
| | | |
| | | |
| | | TaxiPricingDemoService.TaxiPricingService service = new TaxiPricingDemoService.TaxiPricingService(); |
| | | Map<String, BigDecimal> bill = service.calculateOrderPrice(DateUtils.toDate(order.getBoardingTime()), order.getMileageKilometers(), gpsPoints, config); |
| | | |
| | | Integer holidayToday = holidayUtil.isHolidayToday(); |
| | | |
| | | |
| | | Map<String, BigDecimal> bill = service.calculateOrderPrice(DateUtils.toDate(order.getBoardingTime()), order.getMileageKilometers(), gpsPoints, config,holidayToday); |
| | | System.err.println("======= 订单计费账单 ======="); |
| | | bill.forEach((detail, price) -> System.err.println(detail + ": " + price + " 元")); |
| | | |
| | |
| | | xpOrderDetails.add(xpOrderDetail); |
| | | } |
| | | order.setMileageMoney(mileageMoney); |
| | | |
| | | |
| | | for (FareBreakdownDetailVo fareBreakdownDetailVo : longDistance) { |
| | | XpOrderDetail xpOrderDetail = new XpOrderDetail(); |
| | | BeanUtils.copyProperties(fareBreakdownDetailVo, xpOrderDetail); |
| | | xpOrderDetail.setOrderId(orderId); |
| | | xpOrderDetail.setDetailType(4); |
| | | xpOrderDetail.setCreateTime(LocalDateTime.now()); |
| | | mileageMoney = mileageMoney.add(fareBreakdownDetailVo.getMoney()); |
| | | xpOrderDetails.add(xpOrderDetail); |
| | | } |
| | | |
| | | |
| | | for (FareBreakdownDetailVo fareBreakdownDetailVo : duration) { |
| | | XpOrderDetail xpOrderDetail = new XpOrderDetail(); |
| | | BeanUtils.copyProperties(fareBreakdownDetailVo, xpOrderDetail); |
| | | xpOrderDetail.setOrderId(orderId); |
| | | xpOrderDetail.setDetailType(3); |
| | | xpOrderDetail.setCreateTime(LocalDateTime.now()); |
| | | mileageMoney = mileageMoney.add(fareBreakdownDetailVo.getMoney()); |
| | | xpOrderDetails.add(xpOrderDetail); |
| | | } |
| | | |
| | | |
| | | |
| | | for (XpOrderDetail xpOrderDetail : xpOrderDetails) { |
| | | xpOrderDetailMapper.insert(xpOrderDetail); |
| | | } |
| | | for (XpOrderDetail xpOrderDetail : xpOrderDetails) { |
| | | if (xpOrderDetail.getDetailType() == 1) { |
| | | order.setDurationType(xpOrderDetail.getType()); |
| | | order.setDurationMoney(xpOrderDetail.getMoney()); |
| | | order.setDuration(Double.parseDouble(xpOrderDetail.getDuration() + "")); |
| | | } else { |
| | | order.setLongDistanceType(order.getDurationType()); |
| | | order.setLongDistance(xpOrderDetail.getMileage().doubleValue()); |
| | | order.setLongDistancemoney(xpOrderDetail.getMoney()); |
| | | } |
| | | |
| | | for (FareBreakdownDetailVo fareBreakdownDetailVo : duration) { |
| | | if(order.getDurationMoney()==null){ |
| | | order.setDurationMoney(BigDecimal.ZERO); |
| | | } |
| | | BigDecimal add = order.getDurationMoney().add(fareBreakdownDetailVo.getMoney()); |
| | | order.setDurationMoney(add); |
| | | } |
| | | // for (XpOrderDetail xpOrderDetail : xpOrderDetails) { |
| | | // if (xpOrderDetail.getDetailType() == 1) { |
| | | // order.setDurationType(xpOrderDetail.getType()); |
| | | // order.setDurationMoney(xpOrderDetail.getMoney()); |
| | | //// order.setDuration(Double.parseDouble(xpOrderDetail.getDuration() + "")); |
| | | // } else { |
| | | // order.setLongDistanceType(order.getDurationType()); |
| | | // order.setLongDistance(xpOrderDetail.getMileage().doubleValue()); |
| | | // order.setLongDistancemoney(xpOrderDetail.getMoney()); |
| | | // } |
| | | // |
| | | // } |
| | | |
| | | BigDecimal orderMoney = startMoney.add(mileageMoney).add(order.getDurationMoney() != null ? order.getDurationMoney() : BigDecimal.ZERO) |
| | | .add(order.getLongDistancemoney() != null ? order.getLongDistancemoney() : BigDecimal.ZERO) |
| | |
| | | detail.setTime(xpOrderDetail.getTime()); |
| | | detail.setMileage(xpOrderDetail.getMileage()); |
| | | detail.setDuration(xpOrderDetail.getDuration()); |
| | | detail.setMoney(xpOrderDetail.getMoney()); |
| | | if (xpOrderDetail.getDetailType() == 1) { |
| | | start.add(detail); |
| | | } else { |
| | |
| | | package com.xiaopeng.order.utils; |
| | | import com.xiaopeng.order.utils.holiday.HolidayUtil; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalTime; |
| | |
| | | */ |
| | | public class TaxiPricingDemoService { |
| | | |
| | | |
| | | public static void main(String[] args) { |
| | | PricingConfig config = setupMockConfig(); |
| | | // |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.set(2026, Calendar.APRIL, 11, 15, 49, 15); |
| | | Date orderTime = cal.getTime(); |
| | | Date orderTime = new Date(); |
| | | // |
| | | // 模拟总里程 25.0 km,以触发多级远途加价 |
| | | double totalMillige = 9.148; |
| | | double totalMillige = 2.984; |
| | | |
| | | // 模拟 GPS 轨迹点 |
| | | List<GpsPoint> points = createMockGpsPoints(orderTime); |
| | | |
| | | TaxiPricingService service = new TaxiPricingService(); |
| | | Map<String, BigDecimal> bill = service.calculateOrderPrice(orderTime, totalMillige, points, config); |
| | | Map<String, BigDecimal> bill = service.calculateOrderPrice(orderTime, totalMillige, points, config,0); |
| | | |
| | | System.err.println("======= 订单计费账单 ======="); |
| | | bill.forEach((detail, price) -> System.err.println(detail + ": " + price + " 元")); |
| | |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | public static class TaxiPricingService { |
| | | public Map<String, BigDecimal> calculateOrderPrice(Date orderTime, double totalMileageKm, List<GpsPoint> points, PricingConfig config) { |
| | | public Map<String, BigDecimal> calculateOrderPrice(Date orderTime, double totalMileageKm, List<GpsPoint> points, PricingConfig config,Integer holiday) { |
| | | Map<String, BigDecimal> result = new LinkedHashMap<>(); |
| | | BigDecimal totalMileage = BigDecimal.valueOf(totalMileageKm); |
| | | |
| | | PricingRule baseRule = config.findMatchedRule(orderTime); |
| | | PricingRule baseRule = config.findMatchedRule(orderTime,holiday); |
| | | result.put("起步价(" + baseRule.ruleName + ")"+"|"+baseRule.start+"-"+baseRule.end+"|"+baseRule.baseMin+"&"+baseRule.baseKm, baseRule.baseFare); |
| | | |
| | | if (totalMileage.compareTo(baseRule.baseKm) <= 0) { |
| | |
| | | currentTotalM = currentTotalM.add(segM); // 累计当前已行驶的总里程 |
| | | currentTotalMs = currentTotalMs.add(segMs); // 累计当前已行驶的总时间 |
| | | |
| | | PricingRule activeRule = config.findMatchedRule(new Date(curr.getLocatetime())); |
| | | PricingRule activeRule = config.findMatchedRule(new Date(curr.getLocatetime()),holiday); |
| | | |
| | | // 扣除起步额度逻辑 |
| | | BigDecimal billM = BigDecimal.ZERO; |
| | |
| | | public List<PricingRule> normals = new ArrayList<>(); |
| | | public List<LongRangeStep> longSteps = new ArrayList<>(); // 修改为区间列表 |
| | | |
| | | public PricingRule findMatchedRule(Date date) { |
| | | public PricingRule findMatchedRule(Date date,Integer isHoliday) { |
| | | LocalTime t = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime(); |
| | | if (holiday.isMatch(t)) return holiday; |
| | | if (isHoliday==1){ |
| | | return holiday; |
| | | } |
| | | for (PricingRule r : peaks) if (r.isMatch(t)) return r; |
| | | if (night.isMatch(t)) return night; |
| | | for (PricingRule r : normals) if (r.isMatch(t)) return r; |
| | |
| | | |
| | | private static PricingConfig setupMockConfig() { |
| | | PricingConfig config = new PricingConfig(); |
| | | config.peaks.add(new PricingRule("高峰期", "04:00", "05:00", 15.0, 3.0, 10.0, 4, 4)); |
| | | config.peaks.add(new PricingRule("高峰期", "15:00", "16:00", 15.0, 3.0, 10.0, 4, 4)); |
| | | config.night = new PricingRule("夜间行驶", "20:04", "23:00", 15.0, 3.0, 10.0, 3, 3); |
| | | config.holiday = new PricingRule("节假日", "18:47", "18:48", 18.0, 3.0, 5.0, 4, 2.0); |
| | | config.normals.add(new PricingRule("普通时段", "00:00", "23:59", 10.0, 3.0, 10.0, 3, 3)); |
| | | config.peaks.add(new PricingRule("高峰期", "04:00", "05:00", 15, 1, 10, 4, 4)); |
| | | config.peaks.add(new PricingRule("高峰期", "15:00", "16:00", 15, 1, 10, 4, 4)); |
| | | config.night = new PricingRule("夜间行驶", "20:04", "23:00", 15, 1, 10, 3, 3); |
| | | config.holiday = new PricingRule("节假日", "00:00", "23:59", 20, 1, 10, 4, 4); |
| | | config.normals.add(new PricingRule("普通时段", "00:00", "23:59", 10.0, 1, 10.0, 3, 3)); |
| | | |
| | | // --- 远途加价区间配置 (关键修改) --- |
| | | // 1. 超过 num1(12) 不足 num2(20), 加收 num3(1.2) |
| | | config.longSteps.add(new LongRangeStep(5.0, 6.0, 1.2)); |
| | | config.longSteps.add(new LongRangeStep(1, 3, 3)); |
| | | // 2. 超过 num4(20) 不足 num5(35), 加收 num6(2.0) |
| | | config.longSteps.add(new LongRangeStep(6.0, 7.0, 2.0)); |
| | | config.longSteps.add(new LongRangeStep(3, 5, 5)); |
| | | // 3. 超过 num7(35) 以后, 加收 num8(3.5) -> numEnd 传个极大值 |
| | | config.longSteps.add(new LongRangeStep(7.0, 8.0, 3.5)); |
| | | config.longSteps.add(new LongRangeStep(5, 999999, 6)); |
| | | |
| | | return config; |
| | | } |
| | |
| | | list.add(new GpsPoint(162, startTs + 2 * 150 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 160 * 1000)); |
| | | list.add(new GpsPoint(132, startTs + 2 * 170 * 1000)); |
| | | list.add(new GpsPoint(142, startTs + 2 * 180 * 1000)); |
| | | list.add(new GpsPoint(262, startTs + 2 * 190 * 1000)); |
| | | list.add(new GpsPoint(242, startTs + 2 * 200 * 1000)); |
| | | list.add(new GpsPoint(282, startTs + 2 * 210 * 1000)); |
| | | list.add(new GpsPoint(222, startTs + 2 * 220 * 1000)); |
| | | list.add(new GpsPoint(212, startTs + 2 * 230 * 1000)); |
| | | list.add(new GpsPoint(142, startTs + 2 * 240 * 1000)); |
| | | list.add(new GpsPoint(262, startTs + 2 * 250 * 1000)); |
| | | list.add(new GpsPoint(169, startTs + 2 * 260 * 1000)); |
| | | list.add(new GpsPoint(170, startTs + 2 * 270 * 1000)); |
| | | list.add(new GpsPoint(180, startTs + 2 * 280 * 1000)); |
| | | list.add(new GpsPoint(165, startTs + 2 * 290 * 1000)); |
| | | list.add(new GpsPoint(180, startTs + 2 * 300 * 1000)); |
| | | list.add(new GpsPoint(198, startTs + 2 * 310 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 320 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 330 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 340 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 350 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 360 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 370 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 380 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 390 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 400 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 410 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 420 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 430 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 440 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 450 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 460 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 470 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 490 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 500 * 1000)); |
| | | list.add(new GpsPoint(182, startTs + 2 * 510 * 1000)); |
| | | list.add(new GpsPoint(122, startTs + 2 * 180 * 1000)); |
| | | // list.add(new GpsPoint(262, startTs + 2 * 190 * 1000)); |
| | | // list.add(new GpsPoint(242, startTs + 2 * 200 * 1000)); |
| | | // list.add(new GpsPoint(282, startTs + 2 * 210 * 1000)); |
| | | // list.add(new GpsPoint(222, startTs + 2 * 220 * 1000)); |
| | | // list.add(new GpsPoint(212, startTs + 2 * 230 * 1000)); |
| | | // list.add(new GpsPoint(142, startTs + 2 * 240 * 1000)); |
| | | // list.add(new GpsPoint(262, startTs + 2 * 250 * 1000)); |
| | | // list.add(new GpsPoint(169, startTs + 2 * 260 * 1000)); |
| | | // list.add(new GpsPoint(170, startTs + 2 * 270 * 1000)); |
| | | // list.add(new GpsPoint(180, startTs + 2 * 280 * 1000)); |
| | | // list.add(new GpsPoint(165, startTs + 2 * 290 * 1000)); |
| | | // list.add(new GpsPoint(180, startTs + 2 * 300 * 1000)); |
| | | // list.add(new GpsPoint(198, startTs + 2 * 310 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 320 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 330 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 340 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 350 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 360 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 370 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 380 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 390 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 400 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 410 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 420 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 430 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 440 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 450 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 460 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 470 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 490 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 500 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 510 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 520 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 530 * 1000)); |
| | | // list.add(new GpsPoint(182, startTs + 2 * 540 * 1000)); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 发送是否开启倒计时 |
| | | * { |
| | | * "appUserId":"-1", |
| | | * {"type":"OPEN_TRUNK","content":"{\"orderId\":\"1983875114637811713\",\"isOpen\":1}","timestamp":"176569945845456"} |
| | | * } |
| | | * |
| | | * @param dto 消息实体 |
| | | * @return 操作结果 |
| | | */ |
| | | @ApiOperation(value = "发送是否开启倒计时") |
| | | @PostMapping("/inner/websocket/order/sendOpenTrunk") |
| | | public R<String> sendOpenTrunk(@RequestBody SendMessageDTO dto) { |
| | | try { |
| | | String message = dto.getMessage(); |
| | | if (message.trim().isEmpty()) { |
| | | return R.fail("消息内容不能为空"); |
| | | } |
| | | String appUserId = dto.getAppUserId(); |
| | | if (appUserId.trim().isEmpty()) { |
| | | return R.fail("用户id不能为空"); |
| | | } |
| | | int deviceCount = webSocketUserService.sendMessageToUser(appUserId, message); |
| | | if (deviceCount > 0) { |
| | | return R.ok("消息发送成功,发送到 " + deviceCount + " 个设备"); |
| | | } else { |
| | | return R.fail("用户不在线或发送失败"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("向用户发送消息失败", e); |
| | | return R.fail("发送消息失败: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 向指定用户发送JSON格式消息 |
| | | * @param appUserId 用户ID |
| | | * @param request 请求参数 |
| | |
| | | String VEHICLE_COLOR_INVALID = "vehicle.color.invalid"; |
| | | String VEHICLE_ELECTRONIC_NOT_EXISTS = "vehicle.electronic.not.exists"; |
| | | |
| | | // ========== 车辆导入校验 ========== |
| | | String VEHICLE_IMPORT_VALIDATE_FAIL = "vehicle.import.validate.fail"; |
| | | String VEHICLE_IMPORT_CODE_INVALID = "vehicle.import.code.invalid"; |
| | | String VEHICLE_IMPORT_VIN_INVALID = "vehicle.import.vin.invalid"; |
| | | String VEHICLE_IMPORT_PLATE_INVALID = "vehicle.import.plate.invalid"; |
| | | String VEHICLE_IMPORT_COLOR_INVALID = "vehicle.import.color.invalid"; |
| | | String VEHICLE_IMPORT_CODE_DUPLICATE = "vehicle.import.code.duplicate"; |
| | | String VEHICLE_IMPORT_VIN_DUPLICATE = "vehicle.import.vin.duplicate"; |
| | | String VEHICLE_IMPORT_PLATE_DUPLICATE = "vehicle.import.plate.duplicate"; |
| | | String VEHICLE_IMPORT_CODE_EXISTS = "vehicle.import.code.exists"; |
| | | String VEHICLE_IMPORT_VIN_EXISTS = "vehicle.import.vin.exists"; |
| | | String VEHICLE_IMPORT_PLATE_EXISTS = "vehicle.import.plate.exists"; |
| | | |
| | | } |
| | |
| | | import cn.afterturn.easypoi.excel.entity.ExportParams; |
| | | import cn.afterturn.easypoi.excel.entity.ImportParams; |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import cn.hutool.core.lang.Validator; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | |
| | | import java.net.URLEncoder; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | @Api(tags = "车辆管理") |
| | | @RequiredArgsConstructor(onConstructor_ = @Lazy) |
| | | public class XpVehicleController { |
| | | |
| | | private static final Pattern VEHICLE_CODE_PATTERN = Pattern.compile("^[A-Za-z0-9_]{1,5}$"); |
| | | private static final Pattern VEHICLE_VIN_PATTERN = Pattern.compile("^[A-Z0-9]{17}$"); |
| | | |
| | | private final IXpVehicleService xpVehicleService; |
| | | private final IXpFleetVehicleService vehicleService; |
| | |
| | | throw new ServiceException("导入数据为空!", I18nKeyConstant.VEHICLE_IMPORT_DATA_EMPTY); |
| | | } |
| | | validateImportRequiredFields(importList, params.getHeadRows()); |
| | | validateImportBusinessFields(importList, params.getHeadRows()); |
| | | uploadVehiclePicture(importList); |
| | | xpVehicleService.importVehicles(importList); |
| | | return R.ok(); |
| | |
| | | } |
| | | } |
| | | |
| | | private void validateImportBusinessFields(List<XpVehicleImportExcel> importList, int headRows) { |
| | | List<String> errors = new ArrayList<>(); |
| | | Locale locale = LocaleContextHolder.getLocale(); |
| | | |
| | | for (int index = 0; index < importList.size(); index++) { |
| | | XpVehicleImportExcel row = importList.get(index); |
| | | int excelRowNumber = index + headRows + 1; |
| | | |
| | | String vehicleCode = trimToNull(row.getVehicleCode()); |
| | | String vehicleVin = normalizeVin(row.getVehicleVin()); |
| | | String plateNumber = trimToNull(row.getPlateNumber()); |
| | | String vehicleColor = trimToNull(row.getVehicleColor()); |
| | | |
| | | row.setVehicleCode(vehicleCode); |
| | | row.setVehicleVin(vehicleVin); |
| | | row.setPlateNumber(plateNumber); |
| | | row.setVehicleColor(vehicleColor); |
| | | |
| | | if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleCode) && !VEHICLE_CODE_PATTERN.matcher(vehicleCode).matches()) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_INVALID, |
| | | new Object[]{excelRowNumber, vehicleCode}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_CODE_INVALID, |
| | | locale)); |
| | | } |
| | | if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleVin) && !VEHICLE_VIN_PATTERN.matcher(vehicleVin).matches()) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_INVALID, |
| | | new Object[]{excelRowNumber, vehicleVin}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_VIN_INVALID, |
| | | locale)); |
| | | } |
| | | if (org.apache.commons.lang3.StringUtils.isNotBlank(plateNumber) && !Validator.isPlateNumber(plateNumber)) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_INVALID, |
| | | new Object[]{excelRowNumber, plateNumber}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_PLATE_INVALID, |
| | | locale)); |
| | | } |
| | | if (org.apache.commons.lang3.StringUtils.isNotBlank(vehicleColor) && vehicleColor.length() > 2) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_COLOR_INVALID, |
| | | new Object[]{excelRowNumber, vehicleColor}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_COLOR_INVALID, |
| | | locale)); |
| | | } |
| | | } |
| | | |
| | | Set<String> duplicatedCodes = findDuplicated(importList.stream() |
| | | .map(XpVehicleImportExcel::getVehicleCode) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toList())); |
| | | Set<String> duplicatedVins = findDuplicated(importList.stream() |
| | | .map(XpVehicleImportExcel::getVehicleVin) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toList())); |
| | | Set<String> duplicatedPlates = findDuplicated(importList.stream() |
| | | .map(XpVehicleImportExcel::getPlateNumber) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toList())); |
| | | |
| | | for (int index = 0; index < importList.size(); index++) { |
| | | XpVehicleImportExcel row = importList.get(index); |
| | | int excelRowNumber = index + headRows + 1; |
| | | if (duplicatedCodes.contains(row.getVehicleCode())) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_DUPLICATE, |
| | | new Object[]{excelRowNumber, row.getVehicleCode()}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_CODE_DUPLICATE, |
| | | locale)); |
| | | } |
| | | if (duplicatedVins.contains(row.getVehicleVin())) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_DUPLICATE, |
| | | new Object[]{excelRowNumber, row.getVehicleVin()}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_VIN_DUPLICATE, |
| | | locale)); |
| | | } |
| | | if (duplicatedPlates.contains(row.getPlateNumber())) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_DUPLICATE, |
| | | new Object[]{excelRowNumber, row.getPlateNumber()}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_PLATE_DUPLICATE, |
| | | locale)); |
| | | } |
| | | } |
| | | |
| | | Set<String> codeSet = importList.stream() |
| | | .map(XpVehicleImportExcel::getVehicleCode) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toSet()); |
| | | Set<String> vinSet = importList.stream() |
| | | .map(XpVehicleImportExcel::getVehicleVin) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toSet()); |
| | | Set<String> plateSet = importList.stream() |
| | | .map(XpVehicleImportExcel::getPlateNumber) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toSet()); |
| | | |
| | | Set<String> existsCodes = Collections.emptySet(); |
| | | if (!codeSet.isEmpty()) { |
| | | existsCodes = xpVehicleService.lambdaQuery() |
| | | .select(XpVehicle::getVehicleCode) |
| | | .in(XpVehicle::getVehicleCode, codeSet) |
| | | .list() |
| | | .stream() |
| | | .map(XpVehicle::getVehicleCode) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toSet()); |
| | | } |
| | | Set<String> existsVins = Collections.emptySet(); |
| | | if (!vinSet.isEmpty()) { |
| | | existsVins = xpVehicleService.lambdaQuery() |
| | | .select(XpVehicle::getVehicleVin) |
| | | .in(XpVehicle::getVehicleVin, vinSet) |
| | | .list() |
| | | .stream() |
| | | .map(XpVehicle::getVehicleVin) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toSet()); |
| | | } |
| | | Set<String> existsPlates = Collections.emptySet(); |
| | | if (!plateSet.isEmpty()) { |
| | | existsPlates = xpVehicleService.lambdaQuery() |
| | | .select(XpVehicle::getPlateNumber) |
| | | .in(XpVehicle::getPlateNumber, plateSet) |
| | | .list() |
| | | .stream() |
| | | .map(XpVehicle::getPlateNumber) |
| | | .filter(org.apache.commons.lang3.StringUtils::isNotBlank) |
| | | .collect(java.util.stream.Collectors.toSet()); |
| | | } |
| | | |
| | | for (int index = 0; index < importList.size(); index++) { |
| | | XpVehicleImportExcel row = importList.get(index); |
| | | int excelRowNumber = index + headRows + 1; |
| | | if (existsCodes.contains(row.getVehicleCode())) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_CODE_EXISTS, |
| | | new Object[]{excelRowNumber, row.getVehicleCode()}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_CODE_EXISTS, |
| | | locale)); |
| | | } |
| | | if (existsVins.contains(row.getVehicleVin())) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_VIN_EXISTS, |
| | | new Object[]{excelRowNumber, row.getVehicleVin()}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_VIN_EXISTS, |
| | | locale)); |
| | | } |
| | | if (existsPlates.contains(row.getPlateNumber())) { |
| | | errors.add(messageSource.getMessage(I18nKeyConstant.VEHICLE_IMPORT_PLATE_EXISTS, |
| | | new Object[]{excelRowNumber, row.getPlateNumber()}, |
| | | I18nKeyConstant.VEHICLE_IMPORT_PLATE_EXISTS, |
| | | locale)); |
| | | } |
| | | } |
| | | |
| | | if (!errors.isEmpty()) { |
| | | throw new ServiceException("导入校验失败!", I18nKeyConstant.VEHICLE_IMPORT_VALIDATE_FAIL, |
| | | new Object[]{String.join("\n", errors)}); |
| | | } |
| | | } |
| | | |
| | | private static String normalizeVin(String vin) { |
| | | String trimmed = trimToNull(vin); |
| | | return trimmed == null ? null : trimmed.toUpperCase(Locale.ROOT); |
| | | } |
| | | |
| | | private static String trimToNull(String value) { |
| | | if (value == null) { |
| | | return null; |
| | | } |
| | | String trimmed = value.trim(); |
| | | return trimmed.isEmpty() ? null : trimmed; |
| | | } |
| | | |
| | | private static Set<String> findDuplicated(List<String> values) { |
| | | if (values == null || values.isEmpty()) { |
| | | return Collections.emptySet(); |
| | | } |
| | | Set<String> seen = new HashSet<>(); |
| | | Set<String> duplicated = new HashSet<>(); |
| | | for (String value : values) { |
| | | if (!seen.add(value)) { |
| | | duplicated.add(value); |
| | | } |
| | | } |
| | | return duplicated; |
| | | } |
| | | |
| | | private void uploadVehiclePicture(List<XpVehicleImportExcel> importList) { |
| | | for (XpVehicleImportExcel xpVehicleImportExcel : importList) { |
| | | xpVehicleImportExcel.setVehiclePictures(getOssUrl(xpVehicleImportExcel.getVehiclePictures())); |
| | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.lang.Validator; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | 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.pushMessage.SendMessageDTO; |
| | | import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto; |
| | | import com.xiaopeng.api.feignClient.automaticPilot.XpuVinClient; |
| | | 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.pushMessage.XpPushMessageClient; |
| | | import com.xiaopeng.api.model.operation.XpElectronicFence; |
| | | import com.xiaopeng.api.model.operation.XpElectronicFenceArea; |
| | | import com.xiaopeng.api.model.order.XpOrder; |
| | |
| | | import com.xiaopeng.api.vo.vehicleConvoy.VehiclesCommandVo; |
| | | 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; |
| | |
| | | @Service |
| | | public class XpVehicleServiceImpl extends ServiceImpl<XpVehicleMapper, XpVehicle> implements IXpVehicleService { |
| | | |
| | | private static final Pattern VEHICLE_CODE_PATTERN = Pattern.compile("^[A-Za-z0-9_]{5}$"); |
| | | private static final Pattern VEHICLE_CODE_PATTERN = Pattern.compile("^[A-Za-z0-9_]{1,5}$"); |
| | | private static final Pattern VEHICLE_VIN_PATTERN = Pattern.compile("^[A-Z0-9]{17}$"); |
| | | |
| | | @Autowired |
| | |
| | | private MongoTemplate mongoTemplate; |
| | | @Autowired |
| | | private RedisTemplate redisTemplate; |
| | | @Autowired |
| | | private XpPushMessageClient xpPushMessageClient; |
| | | |
| | | @Override |
| | | public List<XpVehicle> listByIds(List<Long> ids) { |
| | |
| | | throw new ServiceException("车辆非P档,无法开启后备箱", I18nKeyConstant.VEHICLE_NOT_P_GEAR); |
| | | } |
| | | vehiclesCommandVo.setCommandCode(VehiclesCommandEnum.DOOR_TRUNK_OPEN.getCommand()); |
| | | if(xpOrder.getOpenTrunk()==0){ |
| | | xpOrder.setOpenTrunk(1); |
| | | } |
| | | if(xpOrder.getOpenTrunk()==1){ |
| | | xpOrder.setOpenTrunk(2); |
| | | // 添加定时任务 |
| | | xpOrderClient.updateOrderStatus(xpOrder.getId(),7); |
| | | // 推送倒计时消息 消息推送 |
| | | Map<String, Object> params = new HashMap<>(); |
| | | Map<String, Object> content = new HashMap<>(); |
| | | content.put("orderId", xpOrder.getId().toString()); |
| | | content.put("isOpen", 1); |
| | | params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc()); |
| | | params.put("content", JSONObject.toJSONString(content)); |
| | | params.put("timestamp", new Date().getTime() + ""); |
| | | String message = JSONObject.toJSONString(params); |
| | | SendMessageDTO sendMessageDTO = new SendMessageDTO(); |
| | | sendMessageDTO.setMessage(message); |
| | | sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId())); |
| | | xpPushMessageClient.sendStatus(sendMessageDTO); |
| | | } |
| | | } |
| | | try { |
| | | String result = vehicleControlUtil.vehiclesCommand(vehiclesCommandVo, xpOrder.getAppUserId()); |
| | | log.info("车辆控制结果:{}", result); |
| | | xpOrderClient.updateOrder(xpOrder); |
| | | return 1; |
| | | } catch (Exception e) { |
| | | log.error("车辆控制异常:{}", e.getMessage()); |
| | |
| | | vehicle.operation.info.incomplete=以下信息未完善,无法开始运营:{0} |
| | | vehicle.batch.operation.condition.not.met=以下车辆不满足运营条件:{0} |
| | | vehicle.time.expired=以下时间已过期,请填写有效日期:{0} |
| | | vehicle.code.invalid=车辆编码格式不正确,仅支持1-5位字母、数字、下划线:{0} |
| | | vehicle.code.exists=车辆编码已存在:{0} |
| | | vehicle.vin.invalid=车辆VIN码格式不正确,仅支持17位大写字母与数字:{0} |
| | | vehicle.vin.exists=车辆VIN码已存在:{0} |
| | | vehicle.plate.invalid=车牌号格式不正确:{0} |
| | | vehicle.plate.exists=车牌号已存在:{0} |
| | | vehicle.color.invalid=车辆颜色长度不能超过2:{0} |
| | | vehicle.electronic.not.exists=选择的运营区域不存在:{0} |
| | | vehicle.import.validate.fail=导入校验失败:\n{0} |
| | | vehicle.import.code.invalid=第{0}行车辆编码格式不正确(1-5位字母/数字/下划线):{1} |
| | | vehicle.import.vin.invalid=第{0}行车辆VIN码格式不正确(17位大写字母与数字):{1} |
| | | vehicle.import.plate.invalid=第{0}行车牌号格式不正确:{1} |
| | | vehicle.import.color.invalid=第{0}行车辆颜色长度不能超过2:{1} |
| | | vehicle.import.code.duplicate=第{0}行车辆编码在导入文件中重复:{1} |
| | | vehicle.import.vin.duplicate=第{0}行车辆VIN码在导入文件中重复:{1} |
| | | vehicle.import.plate.duplicate=第{0}行车牌号在导入文件中重复:{1} |
| | | vehicle.import.code.exists=第{0}行车辆编码已存在:{1} |
| | | vehicle.import.vin.exists=第{0}行车辆VIN码已存在:{1} |
| | | vehicle.import.plate.exists=第{0}行车牌号已存在:{1} |
| | |
| | | vehicle.not.p.gear=The trunk cannot be opened when the vehicle is not in P gear |
| | | vehicle.temperature.up=The highest temperature is 28°C |
| | | vehicle.temperature.down=The lowest temperature is 22°C |
| | | vehicle.code.invalid=Invalid vehicle code (5 chars, letters/numbers/underscore only): {0} |
| | | vehicle.code.invalid=Invalid vehicle code (1-5 chars, letters/numbers/underscore only): {0} |
| | | vehicle.code.exists=Vehicle code already exists: {0} |
| | | vehicle.vin.invalid=Invalid VIN (17 chars, uppercase letters and digits only): {0} |
| | | vehicle.vin.exists=VIN already exists: {0} |
| | |
| | | vehicle.plate.exists=Plate number already exists: {0} |
| | | vehicle.color.invalid=Vehicle color length must be <= 2: {0} |
| | | vehicle.electronic.not.exists=Selected operating area does not exist: {0} |
| | | vehicle.import.validate.fail=Import validation failed:\n{0} |
| | | vehicle.import.code.invalid=Row {0}: invalid vehicle code (1-5 chars, letters/numbers/underscore only): {1} |
| | | vehicle.import.vin.invalid=Row {0}: invalid VIN (17 chars, uppercase letters and digits only): {1} |
| | | vehicle.import.plate.invalid=Row {0}: invalid plate number: {1} |
| | | vehicle.import.color.invalid=Row {0}: vehicle color length must be <= 2: {1} |
| | | vehicle.import.code.duplicate=Row {0}: duplicate vehicle code in file: {1} |
| | | vehicle.import.vin.duplicate=Row {0}: duplicate VIN in file: {1} |
| | | vehicle.import.plate.duplicate=Row {0}: duplicate plate number in file: {1} |
| | | vehicle.import.code.exists=Row {0}: vehicle code already exists: {1} |
| | | vehicle.import.vin.exists=Row {0}: VIN already exists: {1} |
| | | vehicle.import.plate.exists=Row {0}: plate number already exists: {1} |
| | | vehicle.distance.too.long=Too far away, unable to open |
| | |
| | | vehicle.not.p.gear=车辆非P档,无法开启后备箱 |
| | | vehicle.temperature.up=温度最高28℃ |
| | | vehicle.temperature.down=温度最低22℃ |
| | | vehicle.code.invalid=车辆编码格式不正确,仅支持5位字母、数字、下划线:{0} |
| | | vehicle.code.invalid=车辆编码格式不正确,仅支持1-5位字母、数字、下划线:{0} |
| | | vehicle.code.exists=车辆编码已存在:{0} |
| | | vehicle.vin.invalid=车辆VIN码格式不正确,仅支持17位大写字母与数字:{0} |
| | | vehicle.vin.exists=车辆VIN码已存在:{0} |
| | |
| | | vehicle.plate.exists=车牌号已存在:{0} |
| | | vehicle.color.invalid=车辆颜色长度不能超过2:{0} |
| | | vehicle.electronic.not.exists=选择的运营区域不存在:{0} |
| | | vehicle.distance.too.long=距离过远,无法打开 |
| | | vehicle.import.validate.fail=导入校验失败:\n{0} |
| | | vehicle.import.code.invalid=第{0}行车辆编码格式不正确(1-5位字母/数字/下划线):{1} |
| | | vehicle.import.vin.invalid=第{0}行车辆VIN码格式不正确(17位大写字母与数字):{1} |
| | | vehicle.import.plate.invalid=第{0}行车牌号格式不正确:{1} |
| | | vehicle.import.color.invalid=第{0}行车辆颜色长度不能超过2:{1} |
| | | vehicle.import.code.duplicate=第{0}行车辆编码在导入文件中重复:{1} |
| | | vehicle.import.vin.duplicate=第{0}行车辆VIN码在导入文件中重复:{1} |
| | | vehicle.import.plate.duplicate=第{0}行车牌号在导入文件中重复:{1} |
| | | vehicle.import.code.exists=第{0}行车辆编码已存在:{1} |
| | | vehicle.import.vin.exists=第{0}行车辆VIN码已存在:{1} |
| | | vehicle.import.plate.exists=第{0}行车牌号已存在:{1} |
| | | vehicle.distance.too.long=距离过远,无法打开 |
| | |
| | | </foreach> |
| | | </if> |
| | | AND is_deleted = 0 |
| | | AND vehicleType = 2 |
| | | AND vehicle_type = 2 |
| | | </where> |
| | | ORDER BY create_time DESC |
| | | </select> |