diff --git a/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java b/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java index 6769b20..b90d7ae 100644 --- a/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java +++ b/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java @@ -4,6 +4,7 @@ import com.cdzy.common.model.request.PageParam; import com.cdzy.common.model.response.JsonResult; import com.cdzy.user.model.dto.EbikeUserCyclingDto; import com.cdzy.user.model.entity.EbikeOrder; +import com.cdzy.user.model.vo.EbikeOrderVo; import com.cdzy.user.service.EbikeOrderService; import com.ebike.feign.clients.OperationsFeignClient; import com.ebike.feign.model.dto.FeignEbikeDto; @@ -12,7 +13,7 @@ import com.ebike.feign.model.vo.FeignEbikeBikeRadiusVo; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import jakarta.annotation.Resource; -import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -41,13 +42,13 @@ public class EbikeOrderController { /** * 开始骑行(生成订单、开锁) * - * @param orderDto 骑行信息 + * @param orderDto 骑行信息 (返回订单开始时间、开始点位) * @ {@code 200} 添加成功,{@code 500} 添加失败 */ @PostMapping("saveRide") public JsonResult saveRide(@RequestBody @Validated EbikeUserCyclingDto orderDto) { - Long orderId = ebikeOrderService.saveRide(orderDto); - return JsonResult.success(orderId); + EbikeOrderVo result = ebikeOrderService.saveRide(orderDto); + return JsonResult.success(result); } /** @@ -57,7 +58,7 @@ public class EbikeOrderController { * @ {@code 200} 添加成功,{@code 500} 添加失败 */ @GetMapping("checkHistoryOrder") - public JsonResult checkHistoryOrder(@Validated @NotBlank(message = "用户id不能为空") @RequestParam("userId") Long userId) { + public JsonResult checkHistoryOrder(@Validated @NotNull(message = "用户id不能为空") @RequestParam("userId") Long userId) { EbikeOrder userOrders = ebikeOrderService.checkHistoryOrder(userId); return JsonResult.success(userOrders); } diff --git a/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java b/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java index 541e499..9b8cfe2 100644 --- a/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java +++ b/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java @@ -1,7 +1,11 @@ package com.cdzy.user.model.dto; import com.cdzy.user.handler.PGpointDeserializer; +import com.cdzy.user.handler.PGpointSerializer; +import com.cdzy.user.handler.PGpointTypeHandler; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mybatisflex.annotation.Column; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -32,6 +36,9 @@ public class EbikeUserCyclingDto { /** * 骑行起始点 */ + @Column(typeHandler = PGpointTypeHandler.class) + @JsonSerialize(using = PGpointSerializer.class) @JsonDeserialize(using = PGpointDeserializer.class) + @NotNull(message = "骑行起始点不能为空") private PGpoint startPoint; } diff --git a/ebike-user/src/main/java/com/cdzy/user/model/entity/EbikeOrder.java b/ebike-user/src/main/java/com/cdzy/user/model/entity/EbikeOrder.java index f996060..338a5ba 100644 --- a/ebike-user/src/main/java/com/cdzy/user/model/entity/EbikeOrder.java +++ b/ebike-user/src/main/java/com/cdzy/user/model/entity/EbikeOrder.java @@ -113,6 +113,11 @@ public class EbikeOrder implements Serializable { */ private String discountDetails; + /** + * 计费规则 + */ + private String billingRules; + /** * 地理位置GeoHash编码(用于区域优惠分析) */ diff --git a/ebike-user/src/main/java/com/cdzy/user/model/vo/EbikeOrderVo.java b/ebike-user/src/main/java/com/cdzy/user/model/vo/EbikeOrderVo.java new file mode 100644 index 0000000..97f4371 --- /dev/null +++ b/ebike-user/src/main/java/com/cdzy/user/model/vo/EbikeOrderVo.java @@ -0,0 +1,24 @@ +package com.cdzy.user.model.vo; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author: yanglei + * @since: 2025-11-10 15:48 + */ + +@Data +public class EbikeOrderVo { + + /** + * 订单时间 + */ + private Long orderId; + + /** + * 订单编号 + */ + private LocalDateTime orderTime; +} diff --git a/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java b/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java index 03e01d7..ed0316b 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java @@ -2,6 +2,7 @@ package com.cdzy.user.service; import com.cdzy.user.model.dto.EbikeUserCyclingDto; import com.cdzy.user.model.entity.EbikeOrder; +import com.cdzy.user.model.vo.EbikeOrderVo; import com.ebike.feign.model.dto.FeignEbikeDto; import com.ebike.feign.model.dto.FeignOrderPaymentDto; import com.ebike.feign.model.vo.FeignEbikeBikeRadiusVo; @@ -24,7 +25,7 @@ public interface EbikeOrderService extends IService { * @param orderDto 用户骑行信息 * @return 骑行订单 */ - Long saveRide(EbikeUserCyclingDto orderDto); + EbikeOrderVo saveRide(EbikeUserCyclingDto orderDto); /** * 检查历史订单 diff --git a/ebike-user/src/main/java/com/cdzy/user/service/EbikeUserService.java b/ebike-user/src/main/java/com/cdzy/user/service/EbikeUserService.java index b6d9b58..4afa813 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/EbikeUserService.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/EbikeUserService.java @@ -49,4 +49,6 @@ public interface EbikeUserService extends IService { * @param decryptedData 微信用户信息 */ void updateUserInfo(String decryptedData, String openId); + + EbikeUserVo getUserInfoByUserId(Long userId); } diff --git a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java index 57db548..822bd8d 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java @@ -5,9 +5,11 @@ import com.cdzy.common.enums.Code; import com.cdzy.common.ex.EbikeException; import com.cdzy.common.model.response.JsonResult; import com.cdzy.user.enums.OrderStatus; +import com.cdzy.user.enums.OrderType; import com.cdzy.user.mapper.EbikeOrderMapper; import com.cdzy.user.model.dto.EbikeUserCyclingDto; import com.cdzy.user.model.entity.EbikeOrder; +import com.cdzy.user.model.vo.EbikeOrderVo; import com.cdzy.user.service.EbikeOrderService; import com.cdzy.user.utils.RedisUtil; import com.ebike.feign.clients.OperationsFeignClient; @@ -20,7 +22,9 @@ import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.spring.service.impl.ServiceImpl; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.List; import static com.cdzy.user.model.entity.table.EbikeOrderTableDef.EBIKE_ORDER; @@ -48,75 +52,41 @@ public class EbikeOrderImpl extends ServiceImpl im @Resource private ObjectMapper objectMapper; + @Transactional @Override - public Long saveRide(EbikeUserCyclingDto orderDto) { -// Long userId = orderDto.getUserId(); -// // 校验用户当前是否存在订单 -// EbikeOrder history = checkHistoryOrder(userId); -// if (history != null && history.getOrderStatus() == OrderStatus.IN_PROGRESS) { -// throw new RuntimeException("请完成当前订单后再试"); -// } -// if (history != null && history.getOrderStatus() == OrderStatus.PENDING_PAYMENT) { -// throw new RuntimeException("请完成未支付订单后再试"); -// } -// EbikeOrder userOrders = new EbikeOrder(); -// userOrders.setUserId(userId); -// userOrders.setBikeCode(orderDto.getBikeCode()); -// userOrders.setOrderType(OrderType.ONCE); -// userOrders.setStartTime(LocalDateTime.now()); -// // 获取车辆基本信息 -// JsonResult jsonResult = operationsFeignClient.getEbikeInfoByCode(orderDto.getBikeCode()); -// if (jsonResult.getCode() != Code.SUCCESS) { -// throw new RuntimeException("获取车辆信息失败"); -// } -// FeignEbikeBikeInfoVo bikeInfoVo = jsonResult.getData(); -// // 校验车辆是否可用 -// validateBikeUsable(bikeInfoVo); -// // 中控基本信息 -// FeignEbikeEcuInfoVo ecuInfo = bikeInfoVo.getEbikeEcuInfo(); -// JsonResult operationResult = operationsFeignClient.getOperationById(bikeInfoVo.getRegionId()); -// if (operationResult.getCode() != Code.SUCCESS) { -// throw new RuntimeException("获取运营区信息失败"); -// } -// FeignEbikeRegionVo regionDto = operationResult.getData(); -// FeignEbikeConfigurationVo configurationVo = regionDto.getConfigurationVo(); -// -// if (configurationVo == null || Objects.equals(configurationVo.getIsOperate(), EbikeRegionInOperation.OUT)) { -// throw new RuntimeException("当前运营区已停止运营"); -// } -// -// // 使用 Jackson 替换 FastJSON -// Object redisData = redisUtil.get(ecuInfo.getEcuSn()); -// ResGPSDto resGpsDto = objectMapper.convertValue(redisData, ResGPSDto.class); -// boolean pointInOperation = redisUtil.isPointInOperation(resGpsDto.getLongitude(), resGpsDto.getLatitude(), regionDto.getOrgId(), regionDto.getOperationRegionId()); -// if (!pointInOperation) { -// throw new RuntimeException("当前车辆在运营区外"); -// } -// -// //开锁,并且等待结果 -// CompletableFuture stringCompletableFuture = ebikeCoreHandler.executeCommand(ecuInfo, CmdCode.UNLOCK, Long.valueOf(bikeInfoDto.getBikeId()), userId); -// String response = stringCompletableFuture.join(); -// -// try { -// JsonNode jsonNode = objectMapper.readTree(response); -// if (!jsonNode.has("code") || jsonNode.get("code").asInt() != 0) { -// throw new RuntimeException("开锁失败"); -// } -// } catch (JsonProcessingException e) { -// throw new RuntimeException("开锁响应解析失败", e); -// } -// -// //添加借车单量 -// Long siteRegionId = redisUtil.isPointInSiteWithSiteRegionId(resGpsDto.getLongitude(), resGpsDto.getLatitude(), regionDto.getOperationRegionId()); -// operationsFeignClient.addBorrowing(siteRegionId); -// //改变骑行状态-骑行中 -// operationsFeignClient.riding(bikeInfoDto.getBikeId()); -// userOrders.setBikeId(bikeInfoDto.getBikeId()); -// userOrders.setStartLocation(orderDto.getStartPoint()); -// ebikeOrderTransactionMapper.insert(userOrders); -// //处理车辆 -// return userOrders.getOrderId(); - return null; + public EbikeOrderVo saveRide(EbikeUserCyclingDto orderDto) { + Long userId = orderDto.getUserId(); + // 校验用户当前是否存在订单 + EbikeOrder history = checkHistoryOrder(userId); + if (history != null && history.getOrderStatus() == OrderStatus.IN_PROGRESS) { + throw new RuntimeException("请完成当前订单后再试"); + } + if (history != null && history.getOrderStatus() == OrderStatus.PENDING_PAYMENT) { + throw new RuntimeException("请完成未支付订单后再试"); + } + EbikeOrder userOrders = new EbikeOrder(); + userOrders.setUserId(userId); + userOrders.setBikeCode(orderDto.getBikeCode()); + userOrders.setOrderType(OrderType.ONCE); + userOrders.setStartLocation(orderDto.getStartPoint()); + userOrders.setStartTime(LocalDateTime.now()); + save(userOrders); + // todo 开锁 1.开锁成功(骑行) 2.开锁失败(订单标记为已取消) + boolean unlockSuccess = false; + // 远程调用,是否开锁成功 + + // 开锁失败 -> 订单回滚 + if (!unlockSuccess) { + userOrders.setOrderStatus(OrderStatus.CANCELLED); + userOrders.setCancelTime(LocalDateTime.now()); + updateById(userOrders); + throw new EbikeException("开始失败!"); + } + // 状态返回 + EbikeOrderVo userOrder = new EbikeOrderVo(); + userOrder.setOrderId(userOrders.getOrderId()); + userOrder.setOrderTime(userOrders.getCreateTime()); + return userOrder; } @Override diff --git a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeUserServiceImpl.java b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeUserServiceImpl.java index 10c91ec..62605e4 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeUserServiceImpl.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeUserServiceImpl.java @@ -1,6 +1,5 @@ package com.cdzy.user.service.impl; - import cn.dev33.satoken.stp.StpUtil; import com.cdzy.user.enums.UserStatus; import com.cdzy.user.mapper.EbikeUserMapper; @@ -114,7 +113,7 @@ public class EbikeUserServiceImpl extends ServiceImpl verifyRealName(UserValidateDto userValidateDto) { - EbikeUser ebikeUser = ebikeUserService.getById(userValidateDto.getUserId()); - if (ebikeUser == null) { - log.error("用户不存在"); + EbikeUserVo userInfo = ebikeUserService.getUserInfoByUserId(userValidateDto.getUserId()); + if (userInfo == null) { + log.error("用户{}不存在", userValidateDto.getUserId()); return JsonResult.failed("用户不存在"); } + // 校验是否已进行验证 + Integer realNameStatus = userInfo.getUserRealNameStatus(); + if (realNameStatus != null && realNameStatus.equals(RealNameAttestationStatus.CERTIFIED)) { + return JsonResult.failed("用户已实名验证"); + } try { // 1. 加密数据 Map params = new HashMap<>(); diff --git a/ebike-user/src/main/resources/db/init.sql b/ebike-user/src/main/resources/db/init.sql index 04f7b04..4f559da 100644 --- a/ebike-user/src/main/resources/db/init.sql +++ b/ebike-user/src/main/resources/db/init.sql @@ -200,6 +200,7 @@ CREATE TABLE "public"."ebike_order" ( "payment_method" varchar(20) COLLATE "pg_catalog"."default", "coupon_ids" varchar(255) COLLATE "pg_catalog"."default", "discount_details" jsonb, + "billing_rules" jsonb, "geo_hash" varchar(12) COLLATE "pg_catalog"."default", "start_location" point DEFAULT NULL, "end_location" point DEFAULT NULL, @@ -227,6 +228,7 @@ COMMENT ON COLUMN "public"."ebike_order"."payment_time" IS '支付成功时间'; COMMENT ON COLUMN "public"."ebike_order"."payment_method" IS '支付方式:wechat/alipay/balance'; COMMENT ON COLUMN "public"."ebike_order"."coupon_ids" IS '使用卡券ID集合(JSON数组)'; COMMENT ON COLUMN "public"."ebike_order"."discount_details" IS '优惠明细(结构化存储,便于对账)'; +COMMENT ON COLUMN "public"."ebike_order"."billing_rules" IS '计费规则'; COMMENT ON COLUMN "public"."ebike_order"."geo_hash" IS '地理位置GeoHash编码(用于区域优惠分析)'; COMMENT ON COLUMN "public"."ebike_order"."start_location" IS '骑行初始点'; COMMENT ON COLUMN "public"."ebike_order"."end_location" IS '骑行还车点';