不同运营商获取骑行中与待支付的订单列表与结束用户骑行订单

This commit is contained in:
yanglei 2026-02-26 16:17:12 +08:00
parent 7c945c1efd
commit cab2b4e87e
11 changed files with 471 additions and 1 deletions

View File

@ -3,6 +3,8 @@ package com.ebike.feign.clients;
import com.cdzy.common.model.response.JsonResult;
import com.ebike.feign.component.FeignTokenInterceptor;
import com.ebike.feign.config.ExampleFeignConfiguration;
import com.ebike.feign.model.dto.FeignDiffOperatorOrderList;
import com.ebike.feign.model.dto.FeignEbikeCloseOrderDto;
import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto;
import com.ebike.feign.model.dto.FeignEbikePaymentAmountDto;
import com.ebike.feign.model.vo.FeignEbikeRefundOrderDetailVo;
@ -47,4 +49,21 @@ public interface UserFeignClient {
*/
@PostMapping("/ebikeOrder/api/updateOrderAmount")
JsonResult<?> updateOrderAmount(@RequestBody @Validated FeignEbikePaymentAmountDto dto);
/**
* 运维人员手动关闭骑行订单
*
* @param dto 关闭订单参数
*/
@PostMapping("/ebikeOrder/api/closeOrder")
JsonResult<?> closeOrder(FeignEbikeCloseOrderDto dto);
/**
* 获取不同运营商的订单
*
* @param dto 运营商id
* @return 订单列表
*/
@PostMapping("/ebikeOrder/api/getDiffOperatorOrderList")
JsonResult<?> getDiffOperatorOrderList(FeignDiffOperatorOrderList dto);
}

View File

@ -0,0 +1,14 @@
package com.ebike.feign.model.dto;
import lombok.Data;
/**
* @author yanglei
* @since 2026-02-26 15:05
*/
@Data
public class FeignDiffOperatorOrderList {
private Long operatorId;
}

View File

@ -0,0 +1,32 @@
package com.ebike.feign.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author yanglei
* @since 2026-02-26 14:05
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FeignEbikeCloseOrderDto {
/**
* 车辆编号
*/
private String bikeCode;
/**
* 经度
*/
private double lng;
/**
* 维度
*/
private double lat;
}

View File

@ -0,0 +1,86 @@
package com.ebike.feign.model.vo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.mybatisflex.annotation.Column;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.locationtech.jts.geom.Point;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
*
* @author yanglei
* @since 2026-02-26 15:18
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FeignDiffOperatorOrderListVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 订单id
*/
private Long orderId;
/**
* 用户ID关联用户表
*/
private Long userId;
/**
* 运营商ID
*/
private Long operatorId;
/**
* 车辆编码
*/
private String bikeCode;
/**
* 订单状态0-进行中 1-已取消 2-待支付 3-已支付 4-退款中 5-已退款
*/
private Integer orderStatus;
/**
* 订单总金额单位
*/
private BigDecimal totalAmount;
/**
* 实付金额扣除卡券优惠后
*/
private BigDecimal actualAmount;
/**
* 骑行开始时间仅骑行订单有效
*/
private LocalDateTime startTime;
/**
* 骑行结束时间仅骑行订单有效
*/
private LocalDateTime endTime;
/**
* 骑行起始点
*/
private Point startLocation;
/**
* 骑行结束点
*/
private Point endLocation;
}

View File

@ -3,13 +3,25 @@ package com.cdzy.operations.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.cdzy.common.enums.Code;
import com.cdzy.common.ex.EbikeException;
import com.cdzy.common.model.dto.ResGPSDto;
import com.cdzy.common.model.response.CommonStaffInfo;
import com.cdzy.common.model.response.JsonResult;
import com.cdzy.operations.model.dto.EbikeCloseOrderDto;
import com.cdzy.operations.model.entity.EbikeEcuInfo;
import com.cdzy.operations.service.EbikeEcuInfoService;
import com.cdzy.operations.utils.RedisUtil;
import com.ebike.feign.clients.UserFeignClient;
import com.ebike.feign.model.dto.FeignDiffOperatorOrderList;
import com.ebike.feign.model.dto.FeignEbikeCloseOrderDto;
import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto;
import com.ebike.feign.model.dto.FeignEbikePaymentAmountDto;
import jakarta.annotation.Resource;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.PrecisionModel;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -31,6 +43,13 @@ public class EbikeStatisticsController {
@Resource
private UserFeignClient userFeignClient;
@Resource
private RedisUtil redisUtil;
@Resource
private EbikeEcuInfoService ecuInfoService;
/**
* 查询用户订单统计
*
@ -73,4 +92,59 @@ public class EbikeStatisticsController {
return JsonResult.success();
}
/**
* 结束用户骑行订单
*
* @param dto 结束骑行参数
* @return 订单id
*/
@PostMapping("/closeOrder")
public JsonResult<?> closeBikeOrder(@RequestBody @Validated EbikeCloseOrderDto dto) {
// 根据车辆编号获取车辆ecu
EbikeEcuInfo ebikeEcuInfo = ecuInfoService.getEcu(dto.getBikeCode());
// 从redis获取车辆当前位置
ResGPSDto resGPSDto = (ResGPSDto) redisUtil.getEcu(ebikeEcuInfo.getEcuSn());
FeignEbikeCloseOrderDto ebikeCloseOrderDto = FeignEbikeCloseOrderDto.builder()
.bikeCode(dto.getBikeCode())
.lng(resGPSDto.getLongitude())
.lat(resGPSDto.getLatitude())
.build();
//远程调用用户端关锁结束骑行
JsonResult<?> jsonResult = userFeignClient.closeOrder(ebikeCloseOrderDto);
if (jsonResult.getCode() != Code.SUCCESS) {
throw new EbikeException(jsonResult.getMessage());
}
return JsonResult.success(jsonResult.getData());
}
/**
* 不同运营商获取骑行中与待支付的订单列表
*
* @return 订单列表
*/
@GetMapping("getDiffOperatorOrderList")
public JsonResult<?> getDiffOperatorOrderList() {
FeignDiffOperatorOrderList dto = new FeignDiffOperatorOrderList();
long staffId = StpUtil.getLoginIdAsLong();
CommonStaffInfo staffInfo = StpUtil.getSession().getModel(String.valueOf(staffId), CommonStaffInfo.class);
if (staffInfo == null) {
throw new EbikeException("当前用户信息不存在");
}
boolean isSuperAdmin = Optional.ofNullable(staffInfo.getRoles())
.orElse(Collections.emptyList())
.stream()
.anyMatch(role -> "super_admin".equals(role.getRoleCode()));
// 判断是否超级管理员
if (!isSuperAdmin) {
dto.setOperatorId(staffInfo.getOperatorId());
}
JsonResult<?> jsonResult = userFeignClient.getDiffOperatorOrderList(dto);
if (jsonResult.getCode() != Code.SUCCESS) {
throw new EbikeException(jsonResult.getMessage());
}
return JsonResult.success(jsonResult.getData());
}
}

View File

@ -0,0 +1,16 @@
package com.cdzy.operations.model.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* @author yanglei
* @since 2026-02-26 14:13
*/
@Data
public class EbikeCloseOrderDto {
@NotBlank(message = "车辆编号不能为空")
private String bikeCode;
}

View File

@ -9,11 +9,14 @@ import com.cdzy.user.model.dto.EbikeUserCyclingDto;
import com.cdzy.user.model.dto.EbikeUserCyclingEndDto;
import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeDiffOperatorOrderListVo;
import com.cdzy.user.model.vo.EbikeOrderDetailVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.cdzy.user.service.EbikeOrderService;
import com.ebike.feign.clients.PaymentFeignClient;
import com.ebike.feign.model.dto.FeignDiffOperatorOrderList;
import com.ebike.feign.model.dto.FeignEbikeCloseOrderDto;
import com.ebike.feign.model.dto.FeignEbikeDto;
import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto;
import com.ebike.feign.model.dto.FeignEbikePaymentAmountDto;
@ -197,4 +200,26 @@ public class EbikeOrderController {
return JsonResult.success();
}
/**
* 运维人员远程结束订单
*
* @param dto 结束订单参数
*/
@PostMapping("/api/closeOrder")
public JsonResult<?> closeOrder(@RequestBody FeignEbikeCloseOrderDto dto) {
Long orderId = ebikeOrderService.closeOrder(dto);
return JsonResult.success(orderId);
}
/**
* 不同运营商获取骑行中与待支付的订单列表
*
* @param dto 运营商id
* @return 订单列表
*/
@PostMapping("/api/getDiffOperatorOrderList")
public JsonResult<?> getDiffOperatorOrderList(@RequestBody FeignDiffOperatorOrderList dto) {
List<EbikeDiffOperatorOrderListVo> result = ebikeOrderService.getDiffOperatorOrderList(dto);
return JsonResult.success(result);
}
}

View File

@ -63,7 +63,7 @@ public class EbikeOrder implements Serializable {
private Integer orderType;
/**
* 订单状态0-进行中 1-已取消 2-待支付 3-已支付 4-退款中 5-已退款
* 订单状态0-进行中 1-已取消 2-待支付 3-已支付 4-退款中 5-已退款 6-退款申请中 7-退款申请驳回 8-退款失败
*/
@Column(onInsertValue = "0")
private Integer orderStatus;

View File

@ -0,0 +1,95 @@
package com.cdzy.user.model.vo;
import com.cdzy.user.handler.PointDeserializer;
import com.cdzy.user.handler.PointSerializer;
import com.cdzy.user.handler.PointTypeHandler;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.mybatisflex.annotation.Column;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.locationtech.jts.geom.Point;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
*
* @author yanglei
* @since 2026-02-26 15:18
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EbikeDiffOperatorOrderListVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 订单id
*/
private Long orderId;
/**
* 用户ID关联用户表
*/
private Long userId;
/**
* 运营商ID
*/
private Long operatorId;
/**
* 车辆编码
*/
private String bikeCode;
/**
* 订单状态0-进行中 1-已取消 2-待支付 3-已支付 4-退款中 5-已退款
*/
private Integer orderStatus;
/**
* 订单总金额单位
*/
private BigDecimal totalAmount;
/**
* 实付金额扣除卡券优惠后
*/
private BigDecimal actualAmount;
/**
* 骑行开始时间仅骑行订单有效
*/
private LocalDateTime startTime;
/**
* 骑行结束时间仅骑行订单有效
*/
private LocalDateTime endTime;
/**
* 骑行起始点
*/
@Column(typeHandler = PointTypeHandler.class)
@JsonSerialize(using = PointSerializer.class)
@JsonDeserialize(using = PointDeserializer.class)
private Point startLocation;
/**
* 骑行结束点
*/
@Column(typeHandler = PointTypeHandler.class)
@JsonSerialize(using = PointSerializer.class)
@JsonDeserialize(using = PointDeserializer.class)
private Point endLocation;
}

View File

@ -6,10 +6,13 @@ import com.cdzy.user.model.dto.EbikeUserCyclingDto;
import com.cdzy.user.model.dto.EbikeUserCyclingEndDto;
import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeDiffOperatorOrderListVo;
import com.cdzy.user.model.vo.EbikeOrderDetailVo;
import com.cdzy.user.model.vo.EbikeRefundApplyOrderBaseInfoVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.ebike.feign.model.dto.FeignDiffOperatorOrderList;
import com.ebike.feign.model.dto.FeignEbikeCloseOrderDto;
import com.ebike.feign.model.dto.FeignEbikeDto;
import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto;
import com.ebike.feign.model.dto.FeignEbikePaymentAmountDto;
@ -150,4 +153,19 @@ public interface EbikeOrderService extends IService<EbikeOrder> {
* @param tempLockDto 临时锁车参数
*/
void tempLock(EbikeTempLockDto tempLockDto);
/**
* 运维人员远程结束订单
*
* @param dto 结束订单参数
*/
Long closeOrder(FeignEbikeCloseOrderDto dto);
/**
* 获取不同运营商的订单列表
*
* @param dto 运营商id
* @return 订单列表
*/
List<EbikeDiffOperatorOrderListVo> getDiffOperatorOrderList(FeignDiffOperatorOrderList dto);
}

View File

@ -21,6 +21,7 @@ import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.entity.EbikeOrderDetail;
import com.cdzy.user.model.entity.EbikePayment;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeDiffOperatorOrderListVo;
import com.cdzy.user.model.vo.EbikeOrderDetailVo;
import com.cdzy.user.model.vo.EbikeOrderStatisticsVo;
import com.cdzy.user.model.vo.EbikePaymentCostDetailVo;
@ -33,6 +34,8 @@ import com.cdzy.user.service.EbikePaymentService;
import com.cdzy.user.service.EbikeUserRealInfoService;
import com.cdzy.user.utils.StringUtils;
import com.ebike.feign.clients.OperationsFeignClient;
import com.ebike.feign.model.dto.FeignDiffOperatorOrderList;
import com.ebike.feign.model.dto.FeignEbikeCloseOrderDto;
import com.ebike.feign.model.dto.FeignEbikeDto;
import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto;
import com.ebike.feign.model.dto.FeignEbikePaymentAmountDto;
@ -47,6 +50,10 @@ import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.PrecisionModel;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@ -466,6 +473,90 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
this.mapper.update(ebikeOrder);
}
@Override
public Long closeOrder(FeignEbikeCloseOrderDto dto) {
GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);
Point location = geometryFactory.createPoint(new Coordinate(dto.getLng(), dto.getLat()));
// 先校验当前车辆是否存在骑行订单
QueryWrapper queryWrapper = QueryWrapper.create()
.where(EBIKE_ORDER.BIKE_CODE.eq(dto.getBikeCode()))
.where(EBIKE_ORDER.ORDER_STATUS.eq(OrderStatus.IN_PROGRESS));
EbikeOrder order = ebikeOrderTransactionMapper.selectOneByQuery(queryWrapper);
if (Objects.isNull(order)) {
throw new EbikeException("当前车辆不存在骑行订单");
}
order.setEndTime(LocalDateTime.now());
order.setEndLocation(location);
// 关锁
EbikeLockVo ebikeLockVo = new EbikeLockVo();
ebikeLockVo.setBikeCode(dto.getBikeCode());
ebikeLockVo.setPoint(location);
JsonResult<FeignEbikeUserLockDto> jsonResult = operationsFeignClient.lock(ebikeLockVo);
if (jsonResult.getCode() != Code.SUCCESS) {
throw new EbikeException("关锁失败:" + jsonResult.getMessage());
}
FeignEbikeUserLockDto data = jsonResult.getData();
// 订单费用计算
EbikeCostDetailDto ebikeCostDetail = costCalculation(order.getEndTime(), order, data);
// 获取总费用
BigDecimal totalAmount = ebikeCostDetail.getTotalCost();
// 费用为0不生成支付订单直接订单已支付返回订单id
if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
order.setPaymentTime(LocalDateTime.now());
order.setTotalAmount(BigDecimal.ZERO);
order.setActualAmount(BigDecimal.ZERO);
order.setOrderStatus(OrderStatus.PAID);
order.setIsFreeOrder(Boolean.TRUE);
updateById(order);
return order.getOrderId();
}
order.setOrderStatus(OrderStatus.PENDING_PAYMENT);
order.setTotalAmount(totalAmount);
order.setActualAmount(totalAmount);
order.setIsFreeOrder(Boolean.FALSE);
updateById(order);
//生成支付订单
EbikePayment payment = EbikePayment.builder()
.orderId(order.getOrderId())
.costPrice(order.getTotalAmount())
.paymentMethod(EbikePaymentMethod.WECHAT)
.tradeId(StringUtils.generateLongSnowflakeId("tradeId"))
.currency("CNY")
.userId(order.getUserId())
.createBy(order.getUserId())
.operatorId(order.getOperatorId())
.tradeStatus(EbikePaymentTradeStatus.NO_PAYMENT)
.build();
ebikePaymentService.save(payment);
// 保存计算订单详情
List<EbikeOrderDetail> orderDetails = buildOrderDetails(order, ebikeCostDetail);
ebikeOrderDetailService.saveBatch(orderDetails);
return order.getOrderId();
}
@Override
public List<EbikeDiffOperatorOrderListVo> getDiffOperatorOrderList(FeignDiffOperatorOrderList dto) {
QueryWrapper queryWrapper = QueryWrapper.create()
.select(
EBIKE_ORDER.ORDER_ID,
EBIKE_ORDER.USER_ID,
EBIKE_ORDER.OPERATOR_ID,
EBIKE_ORDER.BIKE_CODE,
EBIKE_ORDER.ORDER_STATUS,
EBIKE_ORDER.TOTAL_AMOUNT,
EBIKE_ORDER.ACTUAL_AMOUNT,
EBIKE_ORDER.START_TIME,
EBIKE_ORDER.END_TIME,
EBIKE_ORDER.START_LOCATION,
EBIKE_ORDER.END_LOCATION)
.where(EBIKE_ORDER.OPERATOR_ID.eq(dto.getOperatorId(), Objects.nonNull(dto.getOperatorId())))
.and(EBIKE_ORDER.ORDER_STATUS.in(OrderStatus.IN_PROGRESS, OrderStatus.PENDING_PAYMENT));
return this.mapper.selectListByQueryAs(queryWrapper, EbikeDiffOperatorOrderListVo.class);
}
/**
* 计算增长率并格式化为百分比字符串
*