feat(order): 增加重复购买检查功能

- 为VLOG_VIDEO、RECORDING_SET 和 PHOTO_SET 类型的产品添加重复购买检查
- 使用 sourceMapper 和 videoMapper 查询用户已购买的产品数量- 根据查询结果设置产品数量,避免重复购买
-优化了价格计算流程,先检查缓存再进行重复购买检查
This commit is contained in:
2025-08-31 14:36:24 +08:00
parent a9d64402f2
commit f91b98c68e

View File

@@ -2,7 +2,16 @@ package com.ycwl.basic.controller.mobile;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.pc.order.req.CreateOrderReqVO;
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
import com.ycwl.basic.model.pc.source.req.SourceReqQuery;
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.repository.TemplateRepository;
import com.ycwl.basic.repository.VideoTaskRepository;
import com.ycwl.basic.service.pc.OrderService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.pricing.dto.*;
@@ -18,12 +27,17 @@ import com.ycwl.basic.order.dto.OrderV2PageRequest;
import com.ycwl.basic.order.dto.PaymentParamsRequest;
import com.ycwl.basic.order.dto.PaymentParamsResponse;
import com.ycwl.basic.order.dto.PaymentCallbackResponse;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 移动端订单控制器V2
@@ -40,7 +54,11 @@ public class AppOrderV2Controller {
private final PriceCacheService priceCacheService;
private final IOrderService orderService;
private final OrderService oldOrderService;
private final SourceMapper sourceMapper;
private final VideoMapper videoMapper;
private final VideoTaskRepository videoTaskRepository;
private final TemplateRepository templateRepository;
/**
* 移动端价格计算
* 包含权限验证:验证人脸所属景区与当前用户匹配
@@ -76,14 +94,60 @@ public class AppOrderV2Controller {
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);
// }
PriceCalculationResult cachedResult = priceCacheService.getCachedPriceResult(
currentUserId, scenicId, request.getProducts());
if (cachedResult != null) {
log.info("命中价格缓存: userId={}, scenicId={}, finalAmount={}",
currentUserId, scenicId, cachedResult.getFinalAmount());
return ApiResponse.success(cachedResult);
}
request.getProducts().forEach(product -> {
switch (product.getProductType()) {
case VLOG_VIDEO:
AtomicInteger deviceCount = new AtomicInteger();
List<MemberVideoEntity> videoEntities = videoMapper.listRelationByFaceAndTemplate(face.getId(), Long.valueOf(product.getProductId()));
if (videoEntities != null && !videoEntities.isEmpty()) {
TaskEntity task = videoTaskRepository.getTaskById(videoEntities.getFirst().getTaskId());
if (task != null) {
Map<String, Object> paramJson = JacksonUtil.parseObject(task.getTaskParams(), Map.class);
if (paramJson == null) {
deviceCount.set(1);
} else {
List<String> templatePlaceholder = templateRepository.getTemplatePlaceholder(task.getTemplateId());
paramJson.entrySet().stream()
.filter(entry -> StringUtils.isNumeric(entry.getKey()))
.forEach(entry -> {
List<Object> jsonArray = JacksonUtil.parseArray(JacksonUtil.toJSONString(entry.getValue()), Object.class);
if (jsonArray != null && !jsonArray.isEmpty()) {
for (Object ignored : jsonArray) {
if (templatePlaceholder.contains(entry.getKey())) {
deviceCount.getAndIncrement();
templatePlaceholder.remove(entry.getKey());
}
}
}
});
}
product.setQuantity(deviceCount.get());
}
}
break;
case RECORDING_SET:
case PHOTO_SET:
SourceReqQuery sourceReqQuery = new SourceReqQuery();
sourceReqQuery.setMemberId(currentUserId);
sourceReqQuery.setType(product.getProductType() == ProductType.RECORDING_SET ? 1 : 2);
sourceReqQuery.setFaceId(face.getId());
Integer count = sourceMapper.countUser(sourceReqQuery);
product.setQuantity(count);
break;
default:
log.warn("未知的商品类型,跳过重复购买检查: productType={}", product.getProductType());
break;
}
});
// 转换为标准价格计算请求
PriceCalculationRequest standardRequest = request.toStandardRequest(currentUserId, scenicId);