package com.ycwl.basic.controller.mobile; import com.ycwl.basic.constant.BaseContextHandler; import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.pricing.dto.*; import com.ycwl.basic.pricing.service.IPriceCalculationService; import com.ycwl.basic.service.pc.FaceService; import com.ycwl.basic.service.PriceCacheService; import com.ycwl.basic.model.pc.face.resp.FaceRespVO; import com.ycwl.basic.dto.MobileOrderRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; /** * 移动端订单控制器V2 * 包含价格查询和订单管理功能 */ @Slf4j @RestController @RequestMapping("/api/mobile/order/v2") @RequiredArgsConstructor public class AppOrderV2Controller { private final IPriceCalculationService priceCalculationService; private final FaceService faceService; private final PriceCacheService priceCacheService; /** * 移动端价格计算 * 包含权限验证:验证人脸所属景区与当前用户匹配 * 集成Redis缓存机制,提升查询性能 */ @PostMapping("/calculate") public ApiResponse calculatePrice(@RequestBody MobilePriceCalculationRequest request) { // 获取当前登录用户ID String currentUserIdStr = BaseContextHandler.getUserId(); if (currentUserIdStr == null) { log.warn("移动端价格计算:用户未登录"); return ApiResponse.fail("用户未登录"); } Long currentUserId = Long.valueOf(currentUserIdStr); log.info("移动端价格计算请求: userId={}, faceId={}, products={}", currentUserId, request.getFaceId(), request.getProducts().size()); // 验证faceId参数 if (request.getFaceId() == null) { log.warn("移动端价格计算:faceId参数缺失"); return ApiResponse.fail("faceId参数不能为空"); } // 查询人脸信息进行权限验证 ApiResponse faceResponse = faceService.getById(request.getFaceId()); if (!faceResponse.isSuccess() || faceResponse.getData() == null) { log.warn("移动端价格计算:人脸信息不存在, faceId={}", request.getFaceId()); return ApiResponse.fail("人脸信息不存在"); } FaceRespVO face = faceResponse.getData(); Long scenicId = face.getScenicId(); // 先尝试从Redis缓存获取价格计算结果 PriceCalculationResult cachedResult = priceCacheService.getCachedPriceResult( currentUserId, scenicId, request.getProducts()); if (cachedResult != null) { log.info("命中价格缓存: userId={}, scenicId={}, finalAmount={}", currentUserId, scenicId, cachedResult.getFinalAmount()); return ApiResponse.success(cachedResult); } // 转换为标准价格计算请求 PriceCalculationRequest standardRequest = request.toStandardRequest(currentUserId, scenicId); // 执行价格计算 PriceCalculationResult result = priceCalculationService.calculatePrice(standardRequest); // 将计算结果缓存到Redis String cacheKey = priceCacheService.cachePriceResult(currentUserId, scenicId, request.getProducts(), result); log.info("移动端价格计算完成: userId={}, scenicId={}, originalAmount={}, finalAmount={}, cacheKey={}", currentUserId, scenicId, result.getOriginalAmount(), result.getFinalAmount(), cacheKey); return ApiResponse.success(result); } /** * 移动端下单接口 * 验证价格缓存有效性,确保5分钟内使用缓存价格下单 */ @PostMapping("/add-order") public ApiResponse addOrder(@RequestBody MobileOrderRequest request) { // 获取当前登录用户ID String currentUserIdStr = BaseContextHandler.getUserId(); if (currentUserIdStr == null) { log.warn("移动端下单:用户未登录"); return ApiResponse.fail("用户未登录"); } Long currentUserId = Long.valueOf(currentUserIdStr); log.info("移动端下单请求: userId={}, faceId={}, products={}, expectedFinalAmount={}", currentUserId, request.getFaceId(), request.getProducts().size(), request.getExpectedFinalAmount()); // 验证必填参数 if (request.getFaceId() == null) { log.warn("移动端下单:faceId参数缺失"); return ApiResponse.fail("faceId参数不能为空"); } if (request.getProducts() == null || request.getProducts().isEmpty()) { log.warn("移动端下单:商品列表为空"); return ApiResponse.fail("商品列表不能为空"); } if (request.getExpectedFinalAmount() == null) { log.warn("移动端下单:预期价格参数缺失"); return ApiResponse.fail("预期价格不能为空"); } // 查询人脸信息进行权限验证 ApiResponse faceResponse = faceService.getById(request.getFaceId()); if (!faceResponse.isSuccess() || faceResponse.getData() == null) { log.warn("移动端下单:人脸信息不存在, faceId={}", request.getFaceId()); return ApiResponse.fail("人脸信息不存在"); } FaceRespVO face = faceResponse.getData(); Long scenicId = face.getScenicId(); // 验证并消费价格缓存(一次性使用) PriceCalculationResult cachedResult = priceCacheService.validateAndConsumePriceCache( currentUserId, scenicId, request.getProducts()); if (cachedResult == null) { log.warn("移动端下单:价格缓存已过期或不存在, userId={}, scenicId={}", currentUserId, scenicId); return ApiResponse.fail("价格信息已过期,请重新查询价格后再下单"); } // 验证价格是否匹配 if (cachedResult.getFinalAmount().compareTo(request.getExpectedFinalAmount()) != 0) { log.warn("移动端下单:价格不匹配, cached={}, expected={}, userId={}, scenicId={}", cachedResult.getFinalAmount(), request.getExpectedFinalAmount(), currentUserId, scenicId); return ApiResponse.fail("价格信息不匹配,请重新查询价格后再下单"); } // 验证原价是否匹配(可选) if (request.getExpectedOriginalAmount() != null && cachedResult.getOriginalAmount().compareTo(request.getExpectedOriginalAmount()) != 0) { log.warn("移动端下单:原价不匹配, cached={}, expected={}, userId={}, scenicId={}", cachedResult.getOriginalAmount(), request.getExpectedOriginalAmount(), currentUserId, scenicId); return ApiResponse.fail("原价信息不匹配,请重新查询价格后再下单"); } log.info("价格缓存验证通过: userId={}, scenicId={}, finalAmount={}", currentUserId, scenicId, cachedResult.getFinalAmount()); // TODO: 实现订单创建逻辑 // 1. 生成订单号 // 2. 创建订单基础信息 // 3. 保存订单商品明细 // 4. 记录使用的优惠券和券码信息 // 5. 更新优惠券和券码状态 // 6. 初始化订单状态为待支付 // 7. 发送订单创建成功通知 String orderId = "ORDER_" + System.currentTimeMillis(); // 临时订单号生成逻辑 log.info("移动端订单创建成功: orderId={}, userId={}, scenicId={}, finalAmount={}", orderId, currentUserId, scenicId, cachedResult.getFinalAmount()); return ApiResponse.success(orderId); } }