You've already forked FrameTour-BE
Compare commits
10 Commits
3b11ddef6a
...
5cc32ddf61
| Author | SHA1 | Date | |
|---|---|---|---|
| 5cc32ddf61 | |||
| 07987835ec | |||
| 0a3f4119d7 | |||
| 51c7de2474 | |||
| 773d7f2254 | |||
| af131131ed | |||
| 3f6f1508c5 | |||
| dbee1d9709 | |||
| 83d1096fdb | |||
| 82925d203c |
@@ -230,6 +230,9 @@ public class OrderBiz {
|
||||
orderRepository.updateOrder(orderId, orderUpdate);
|
||||
orderItems.forEach(item -> {
|
||||
switch (item.getGoodsType()) {
|
||||
case -1: // vlog视频模板
|
||||
videoRepository.setUserIsBuyTemplate(order.getMemberId(), item.getGoodsId(), order.getId(), order.getFaceId());
|
||||
break;
|
||||
case 0: // vlog视频
|
||||
videoRepository.setUserIsBuyItem(order.getMemberId(), item.getGoodsId(), order.getId());
|
||||
break;
|
||||
@@ -311,10 +314,14 @@ public class OrderBiz {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否购买了指定商品
|
||||
* 提供给PriceBiz使用,避免循环调用
|
||||
* 检查用户是否购买了指定商品,并额外校验订单的faceId是否匹配
|
||||
* @param userId 用户ID
|
||||
* @param faceId 人脸ID
|
||||
* @param goodsType 商品类型
|
||||
* @param goodsId 商品ID
|
||||
* @return 是否已购买且faceId匹配
|
||||
*/
|
||||
public boolean checkUserBuyItem(Long userId, int goodsType, Long goodsId) {
|
||||
return orderRepository.checkUserBuyItem(userId, goodsType, goodsId);
|
||||
public boolean checkUserBuyFaceItem(Long userId, Long faceId, int goodsType, Long goodsId) {
|
||||
return orderRepository.checkUserBuyFaceItem(userId, faceId, goodsType, goodsId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,14 @@ public class PriceBiz {
|
||||
goodsList.add(new GoodsListRespVO(2L, "照片集", 2));
|
||||
}
|
||||
}
|
||||
// 拼图
|
||||
puzzleTemplateMapper.list(scenicId, null, 1).forEach(puzzleTemplate -> {
|
||||
GoodsListRespVO goods = new GoodsListRespVO();
|
||||
goods.setGoodsId(puzzleTemplate.getId());
|
||||
goods.setGoodsName(puzzleTemplate.getName());
|
||||
goods.setGoodsType(5);
|
||||
goodsList.add(goods);
|
||||
});
|
||||
return goodsList;
|
||||
}
|
||||
|
||||
@@ -125,6 +133,7 @@ public class PriceBiz {
|
||||
|
||||
case "PHOTO_LOG":
|
||||
// 从 template 表查询pLog模板
|
||||
goodsList.add(new SimpleGoodsRespVO(scenicId, "pLog图<景区打包>", productType));
|
||||
List<PuzzleTemplateEntity> puzzleList = puzzleTemplateMapper.list(scenicId, null, null);
|
||||
puzzleList.stream()
|
||||
.map(template -> new SimpleGoodsRespVO(template.getId(), template.getName(), productType))
|
||||
@@ -272,7 +281,7 @@ public class PriceBiz {
|
||||
allContentsPurchased = false;
|
||||
break;
|
||||
}
|
||||
boolean hasPurchasedTemplate = orderBiz.checkUserBuyItem(userId, -1, videoEntities.getFirst().getVideoId());
|
||||
boolean hasPurchasedTemplate = orderBiz.checkUserBuyFaceItem(userId, faceId, -1, videoEntities.getFirst().getVideoId());
|
||||
if (!hasPurchasedTemplate) {
|
||||
allContentsPurchased = false;
|
||||
break;
|
||||
@@ -284,7 +293,7 @@ public class PriceBiz {
|
||||
if (scenicConfig != null) {
|
||||
// 检查录像集
|
||||
if (!Boolean.TRUE.equals(scenicConfig.getDisableSourceVideo())) {
|
||||
boolean hasPurchasedRecording = orderBiz.checkUserBuyItem(userId, 1, faceId);
|
||||
boolean hasPurchasedRecording = orderBiz.checkUserBuyFaceItem(userId, faceId, 1, faceId);
|
||||
if (!hasPurchasedRecording) {
|
||||
allContentsPurchased = false;
|
||||
}
|
||||
@@ -292,7 +301,7 @@ public class PriceBiz {
|
||||
|
||||
// 检查照片集
|
||||
if (allContentsPurchased && !Boolean.TRUE.equals(scenicConfig.getDisableSourceImage())) {
|
||||
boolean hasPurchasedPhoto = orderBiz.checkUserBuyItem(userId, 2, faceId);
|
||||
boolean hasPurchasedPhoto = orderBiz.checkUserBuyFaceItem(userId, faceId, 2, faceId);
|
||||
if (!hasPurchasedPhoto) {
|
||||
allContentsPurchased = false;
|
||||
}
|
||||
|
||||
@@ -205,26 +205,31 @@ public class AppPuzzleController {
|
||||
|
||||
// 设置模板ID
|
||||
vo.setTemplateId(record.getTemplateId());
|
||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), 5, record.getTemplateId());
|
||||
if (isBuyRespVO.isBuy()) {
|
||||
IsBuyRespVO isBuyScenic = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), 5, face.getScenicId());
|
||||
if (isBuyScenic.isBuy()) {
|
||||
vo.setIsBuy(1);
|
||||
} else {
|
||||
vo.setIsBuy(0);
|
||||
PriceCalculationRequest calculationRequest = new PriceCalculationRequest();
|
||||
ProductItem productItem = new ProductItem();
|
||||
productItem.setProductType(ProductType.PHOTO_LOG);
|
||||
productItem.setProductId(record.getTemplateId().toString());
|
||||
productItem.setPurchaseCount(1);
|
||||
productItem.setScenicId(face.getScenicId().toString());
|
||||
calculationRequest.setProducts(Collections.singletonList(productItem));
|
||||
calculationRequest.setUserId(face.getMemberId());
|
||||
calculationRequest.setFaceId(record.getFaceId());
|
||||
calculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult calculationResult = iPriceCalculationService.calculatePrice(calculationRequest);
|
||||
if (calculationResult.getFinalAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
vo.setFreeCount(0);
|
||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), 5, record.getTemplateId());
|
||||
if (isBuyRespVO.isBuy()) {
|
||||
vo.setIsBuy(1);
|
||||
} else {
|
||||
vo.setFreeCount(1);
|
||||
vo.setIsBuy(0);
|
||||
PriceCalculationRequest calculationRequest = new PriceCalculationRequest();
|
||||
ProductItem productItem = new ProductItem();
|
||||
productItem.setProductType(ProductType.PHOTO_LOG);
|
||||
productItem.setProductId(record.getTemplateId().toString());
|
||||
productItem.setPurchaseCount(1);
|
||||
productItem.setScenicId(face.getScenicId().toString());
|
||||
calculationRequest.setProducts(Collections.singletonList(productItem));
|
||||
calculationRequest.setUserId(face.getMemberId());
|
||||
calculationRequest.setFaceId(record.getFaceId());
|
||||
calculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult calculationResult = iPriceCalculationService.calculatePrice(calculationRequest);
|
||||
if (calculationResult.getFinalAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
vo.setFreeCount(0);
|
||||
} else {
|
||||
vo.setFreeCount(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return vo;
|
||||
|
||||
@@ -55,7 +55,7 @@ public class AppTaskController {
|
||||
|
||||
@PostMapping("/submit")
|
||||
public ApiResponse<String> submitVideoTask(@RequestBody VideoTaskReq videoTaskReq) {
|
||||
taskService.createTaskByFaceIdAndTemplateId(videoTaskReq.getFaceId(),videoTaskReq.getTemplateId(),0);
|
||||
taskService.createTaskByFaceIdAndTemplateId(videoTaskReq.getFaceId(),videoTaskReq.getTemplateId(),false);
|
||||
return ApiResponse.success("成功");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,22 +74,31 @@ public class PuzzleGenerationOrchestrator {
|
||||
// 3. 准备公共动态数据
|
||||
Map<String, String> baseDynamicData = buildBaseDynamicData(faceId, faceUrl, scenicBasic);
|
||||
|
||||
// 4. 遍历所有模板,逐个生成
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
for (PuzzleTemplateDTO template : templateList) {
|
||||
try {
|
||||
generateSingleTemplate(scenicId, faceId, memberId, template, baseDynamicData);
|
||||
successCount++;
|
||||
} catch (Exception e) {
|
||||
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName(), e);
|
||||
failCount++;
|
||||
}
|
||||
// 4. 使用虚拟线程池并行生成所有模板
|
||||
java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0);
|
||||
java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0);
|
||||
|
||||
try (java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()) {
|
||||
// 为每个模板创建一个异步任务
|
||||
List<java.util.concurrent.CompletableFuture<Void>> futures = templateList.stream()
|
||||
.map(template -> java.util.concurrent.CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
generateSingleTemplate(scenicId, faceId, memberId, template, baseDynamicData);
|
||||
successCount.incrementAndGet();
|
||||
} catch (Exception e) {
|
||||
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName(), e);
|
||||
failCount.incrementAndGet();
|
||||
}
|
||||
}, executor))
|
||||
.toList();
|
||||
|
||||
// 等待所有任务完成
|
||||
java.util.concurrent.CompletableFuture.allOf(futures.toArray(new java.util.concurrent.CompletableFuture[0])).join();
|
||||
}
|
||||
|
||||
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
|
||||
scenicId, templateList.size(), successCount, failCount);
|
||||
scenicId, templateList.size(), successCount.get(), failCount.get());
|
||||
|
||||
} catch (Exception e) {
|
||||
// 异步任务失败不影响主流程,仅记录日志
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.ycwl.basic.puzzle.fill.datasource;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.ycwl.basic.mapper.SourceMapper;
|
||||
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||
import com.ycwl.basic.puzzle.fill.enums.DataSourceType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 设备缩略图数据源策略
|
||||
* 根据deviceIndex指定第N个设备的缩略图
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DeviceThumbImageDataSourceStrategy implements DataSourceStrategy {
|
||||
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
|
||||
@Override
|
||||
public String resolve(JsonNode sourceFilter, String sortStrategy, DataSourceContext context) {
|
||||
try {
|
||||
// 默认type=2(图片)
|
||||
Integer type = 2;
|
||||
if (sourceFilter != null && sourceFilter.has("type")) {
|
||||
type = sourceFilter.get("type").asInt();
|
||||
}
|
||||
|
||||
// 获取deviceIndex
|
||||
Integer deviceIndex = 0;
|
||||
if (sourceFilter != null && sourceFilter.has("deviceIndex")) {
|
||||
deviceIndex = sourceFilter.get("deviceIndex").asInt();
|
||||
}
|
||||
|
||||
// 使用默认策略
|
||||
if (sortStrategy == null || sortStrategy.isEmpty()) {
|
||||
sortStrategy = "LATEST";
|
||||
}
|
||||
|
||||
// 1. 检查是否有过滤后的机位列表
|
||||
Map<String, Object> extra = context.getExtra();
|
||||
if (extra != null && extra.containsKey("filteredDeviceIds")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> filteredDeviceIds = (List<Long>) extra.get("filteredDeviceIds");
|
||||
|
||||
if (filteredDeviceIds != null && !filteredDeviceIds.isEmpty()) {
|
||||
// 使用过滤后的机位列表
|
||||
if (deviceIndex >= filteredDeviceIds.size()) {
|
||||
log.warn("deviceIndex[{}]超出过滤后的机位列表范围, 最大索引={}",
|
||||
deviceIndex, filteredDeviceIds.size() - 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
Long targetDeviceId = filteredDeviceIds.get(deviceIndex);
|
||||
log.debug("使用过滤后的机位列表, deviceIndex={}, targetDeviceId={}",
|
||||
deviceIndex, targetDeviceId);
|
||||
|
||||
SourceEntity source = sourceMapper.getSourceByFaceAndDeviceId(
|
||||
context.getFaceId(),
|
||||
targetDeviceId,
|
||||
type,
|
||||
sortStrategy
|
||||
);
|
||||
|
||||
if (source != null) {
|
||||
String thumbUrl = source.getThumbUrl();
|
||||
log.debug("解析DEVICE_THUMB_IMAGE成功(过滤模式), faceId={}, deviceId={}, type={}, thumbUrl={}",
|
||||
context.getFaceId(), targetDeviceId, type, thumbUrl);
|
||||
return thumbUrl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 降级到原有逻辑(使用deviceIndex直接查询)
|
||||
SourceEntity source = sourceMapper.getSourceByFaceAndDeviceIndex(
|
||||
context.getFaceId(),
|
||||
deviceIndex,
|
||||
type,
|
||||
sortStrategy
|
||||
);
|
||||
|
||||
if (source != null) {
|
||||
String thumbUrl = source.getThumbUrl();
|
||||
log.debug("解析DEVICE_THUMB_IMAGE成功(索引模式), faceId={}, deviceIndex={}, type={}, thumbUrl={}",
|
||||
context.getFaceId(), deviceIndex, type, thumbUrl);
|
||||
return thumbUrl;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析DEVICE_THUMB_IMAGE异常, faceId={}", context.getFaceId(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSupportedType() {
|
||||
return DataSourceType.DEVICE_THUMB_IMAGE.getCode();
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ public enum DataSourceType {
|
||||
* 设备图片(根据deviceIndex指定第N个设备的图片)
|
||||
*/
|
||||
DEVICE_IMAGE("DEVICE_IMAGE", "设备图片"),
|
||||
DEVICE_THUMB_IMAGE("DEVICE_THUMB_IMAGE", "设备缩略图片"),
|
||||
|
||||
/**
|
||||
* 静态值(直接使用fallbackValue)
|
||||
|
||||
@@ -23,7 +23,7 @@ public class OrderRepository {
|
||||
public static final String ORDER_CACHE_KEY = "order:%s";
|
||||
public static final String ORDER_ITEMS_CACHE_KEY = "order:%s:items";
|
||||
public static final String ORDER_ITEM_CACHE_KEY = "order:item:%s";
|
||||
public static final String ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY = "order:user:%s:type:%s:id:%s";
|
||||
public static final String ORDER_USER_FACE_TYPE_BUY_ITEM_CACHE_KEY = "order:user:%s:face:%s:type:%s:id:%s";
|
||||
|
||||
public OrderEntity getOrder(Long orderId) {
|
||||
if (redisTemplate.hasKey(String.format(ORDER_CACHE_KEY, orderId))) {
|
||||
@@ -62,40 +62,12 @@ public class OrderRepository {
|
||||
return orderItemEntity;
|
||||
}
|
||||
|
||||
public boolean checkUserBuyItem(Long userId, int goodsType, Long goodsId) {
|
||||
synchronized (this) {
|
||||
if (redisTemplate.hasKey(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId))) {
|
||||
return "1".equals(redisTemplate.opsForValue().get(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId)));
|
||||
}
|
||||
OrderEntity orderEntity = orderMapper.getUserBuyItem(userId, goodsType, goodsId);
|
||||
if (orderEntity == null) {
|
||||
redisTemplate.opsForValue().set(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId), "0", 60, TimeUnit.SECONDS);
|
||||
return false;
|
||||
}
|
||||
if (Integer.valueOf(1).equals(orderEntity.getStatus())) {
|
||||
redisTemplate.opsForValue().set(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId), "1");
|
||||
return true;
|
||||
} else {
|
||||
redisTemplate.opsForValue().set(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId), "0", 60, TimeUnit.SECONDS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public OrderEntity getUserBuyItem(Long userId, int goodsType, Long goodsId) {
|
||||
return orderMapper.getUserBuyItem(userId, goodsType, goodsId);
|
||||
}
|
||||
|
||||
public void clearUserBuyItemCache(Long userId, int goodsType, Long goodsId) {
|
||||
redisTemplate.delete(String.format(ORDER_USER_TYPE_BUY_ITEM_CACHE_KEY, userId, goodsType, goodsId));
|
||||
}
|
||||
|
||||
public void clearOrderCache(Long orderId) {
|
||||
OrderEntity order = getOrder(orderId);
|
||||
redisTemplate.delete(String.format(ORDER_CACHE_KEY, orderId));
|
||||
getOrderItems(orderId).forEach(orderItem -> {
|
||||
redisTemplate.delete(String.format(ORDER_ITEM_CACHE_KEY, orderItem.getId()));
|
||||
clearUserBuyItemCache(order.getMemberId(), orderItem.getGoodsType(), orderItem.getGoodsId());
|
||||
clearUserBuyFaceItemCache(order.getMemberId(), order.getFaceId(), orderItem.getGoodsType(), orderItem.getGoodsId());
|
||||
});
|
||||
redisTemplate.delete(String.format(ORDER_ITEMS_CACHE_KEY, orderId));
|
||||
}
|
||||
@@ -105,4 +77,37 @@ public class OrderRepository {
|
||||
orderMapper.updateOrder(updateEntity);
|
||||
clearOrderCache(orderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否购买了指定商品,并额外校验订单的faceId是否匹配
|
||||
* @param userId 用户ID
|
||||
* @param faceId 人脸ID
|
||||
* @param goodsType 商品类型
|
||||
* @param goodsId 商品ID
|
||||
* @return 是否已购买且faceId匹配
|
||||
*/
|
||||
public boolean checkUserBuyFaceItem(Long userId, Long faceId, int goodsType, Long goodsId) {
|
||||
synchronized (this) {
|
||||
String cacheKey = String.format(ORDER_USER_FACE_TYPE_BUY_ITEM_CACHE_KEY, userId, faceId, goodsType, goodsId);
|
||||
if (redisTemplate.hasKey(cacheKey)) {
|
||||
return "1".equals(redisTemplate.opsForValue().get(cacheKey));
|
||||
}
|
||||
OrderEntity orderEntity = orderMapper.getUserBuyFaceItem(userId, faceId, goodsType, goodsId);
|
||||
if (orderEntity == null) {
|
||||
redisTemplate.opsForValue().set(cacheKey, "0", 60, TimeUnit.SECONDS);
|
||||
return false;
|
||||
}
|
||||
if (Integer.valueOf(1).equals(orderEntity.getStatus())) {
|
||||
redisTemplate.opsForValue().set(cacheKey, "1");
|
||||
return true;
|
||||
} else {
|
||||
redisTemplate.opsForValue().set(cacheKey, "0", 60, TimeUnit.SECONDS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearUserBuyFaceItemCache(Long userId, Long faceId, int goodsType, Long goodsId) {
|
||||
redisTemplate.delete(String.format(ORDER_USER_FACE_TYPE_BUY_ITEM_CACHE_KEY, userId, faceId, goodsType, goodsId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package com.ycwl.basic.repository;
|
||||
|
||||
import com.ycwl.basic.biz.PriceBiz;
|
||||
import com.ycwl.basic.model.mobile.order.IsBuyBatchRespVO;
|
||||
import com.ycwl.basic.pricing.dto.VoucherInfo;
|
||||
import com.ycwl.basic.pricing.enums.VoucherDiscountType;
|
||||
import com.ycwl.basic.pricing.service.IVoucherService;
|
||||
import com.ycwl.basic.utils.JacksonUtil;
|
||||
import com.ycwl.basic.mapper.VideoMapper;
|
||||
@@ -116,4 +113,25 @@ public class VideoRepository {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setUserIsBuyTemplate(Long memberId, Long templateId, Long orderId, Long faceId) {
|
||||
List<MemberVideoEntity> videoEntities = memberRelationRepository.listRelationByFace(faceId);
|
||||
for (MemberVideoEntity videoEntity : videoEntities) {
|
||||
if (videoEntity.getTemplateId() != null && videoEntity.getTemplateId().equals(templateId)) {
|
||||
MemberVideoEntity memberVideo = new MemberVideoEntity();
|
||||
memberVideo.setVideoId(videoEntity.getVideoId());
|
||||
memberVideo.setMemberId(memberId);
|
||||
memberVideo.setIsBuy(1);
|
||||
memberVideo.setOrderId(orderId);
|
||||
videoMapper.updateRelation(memberVideo);
|
||||
|
||||
// 清理视频关系缓存
|
||||
MemberVideoEntity existingVideo = videoMapper.queryUserVideo(memberId, videoEntity.getVideoId());
|
||||
if (existingVideo != null && existingVideo.getFaceId() != null) {
|
||||
memberRelationRepository.clearVCacheByFace(existingVideo.getFaceId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,9 +473,9 @@ public class FaceServiceImpl implements FaceService {
|
||||
contentPageVO.setLockType(1);
|
||||
}
|
||||
}
|
||||
boolean buy = orderBiz.checkUserBuyItem(userId, contentPageVO.getGoodsType(), contentPageVO.getContentId());
|
||||
boolean buy = orderBiz.checkUserBuyFaceItem(userId, faceId, contentPageVO.getGoodsType(), contentPageVO.getContentId());
|
||||
if (!buy) {
|
||||
buy = orderBiz.checkUserBuyItem(userId, -1, contentPageVO.getTemplateId());
|
||||
buy = orderBiz.checkUserBuyFaceItem(userId, faceId, -1, contentPageVO.getTemplateId());
|
||||
}
|
||||
if (buy) {
|
||||
contentPageVO.setIsBuy(1);
|
||||
@@ -487,21 +487,25 @@ public class FaceServiceImpl implements FaceService {
|
||||
List<PuzzleTemplateEntity> puzzleTemplateEntityList = puzzleTemplateMapper.list(face.getScenicId(), null, 1);
|
||||
if (!puzzleTemplateEntityList.isEmpty()) {
|
||||
List<PuzzleGenerationRecordEntity> records = puzzleGenerationRecordMapper.listByFaceId(faceId);
|
||||
puzzleTemplateEntityList.forEach(template -> {
|
||||
Optional<PuzzleGenerationRecordEntity> optionalRecord = records.stream().filter(r -> r.getTemplateId().equals(template.getId())).findFirst();
|
||||
ContentPageVO sfpContent = new ContentPageVO();
|
||||
sfpContent.setName(template.getName());
|
||||
sfpContent.setGroup("plog");
|
||||
sfpContent.setScenicId(face.getScenicId());
|
||||
sfpContent.setContentType(3);
|
||||
sfpContent.setSourceType(3);
|
||||
sfpContent.setLockType(-1);
|
||||
sfpContent.setContentId(optionalRecord.map(PuzzleGenerationRecordEntity::getId).orElse(null));
|
||||
sfpContent.setTemplateId(template.getId());
|
||||
sfpContent.setTemplateCoverUrl(template.getCoverImage());
|
||||
sfpContent.setGoodsType(3);
|
||||
sfpContent.setSort(0);
|
||||
if (optionalRecord.isPresent()) {
|
||||
PuzzleTemplateEntity template = puzzleTemplateEntityList.getFirst();
|
||||
Optional<PuzzleGenerationRecordEntity> optionalRecord = records.stream().filter(r -> r.getTemplateId().equals(template.getId())).findFirst();
|
||||
ContentPageVO sfpContent = new ContentPageVO();
|
||||
sfpContent.setName(template.getName());
|
||||
sfpContent.setGroup("plog");
|
||||
sfpContent.setScenicId(face.getScenicId());
|
||||
sfpContent.setContentType(3);
|
||||
sfpContent.setSourceType(3);
|
||||
sfpContent.setLockType(-1);
|
||||
sfpContent.setContentId(optionalRecord.map(PuzzleGenerationRecordEntity::getId).orElse(null));
|
||||
sfpContent.setTemplateId(template.getId());
|
||||
sfpContent.setTemplateCoverUrl(template.getCoverImage());
|
||||
sfpContent.setGoodsType(3);
|
||||
sfpContent.setSort(0);
|
||||
if (optionalRecord.isPresent()) {
|
||||
IsBuyRespVO isBuyScenic = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), faceId, 5, face.getScenicId());
|
||||
if (isBuyScenic.isBuy()) {
|
||||
sfpContent.setIsBuy(1);
|
||||
} else {
|
||||
IsBuyRespVO isBuyRespVO = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), faceId, 5, optionalRecord.get().getTemplateId());
|
||||
if (isBuyRespVO.isBuy()) {
|
||||
sfpContent.setIsBuy(1);
|
||||
@@ -509,24 +513,24 @@ public class FaceServiceImpl implements FaceService {
|
||||
sfpContent.setIsBuy(0);
|
||||
}
|
||||
}
|
||||
PriceCalculationRequest calculationRequest = new PriceCalculationRequest();
|
||||
ProductItem productItem = new ProductItem();
|
||||
productItem.setProductType(ProductType.PHOTO_LOG);
|
||||
productItem.setProductId(template.getId().toString());
|
||||
productItem.setPurchaseCount(1);
|
||||
productItem.setScenicId(face.getScenicId().toString());
|
||||
calculationRequest.setProducts(Collections.singletonList(productItem));
|
||||
calculationRequest.setUserId(face.getMemberId());
|
||||
calculationRequest.setFaceId(face.getId());
|
||||
calculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult calculationResult = iPriceCalculationService.calculatePrice(calculationRequest);
|
||||
if (calculationResult.getFinalAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
sfpContent.setFreeCount(0);
|
||||
} else {
|
||||
sfpContent.setFreeCount(1);
|
||||
}
|
||||
contentList.add(1, sfpContent);
|
||||
});
|
||||
}
|
||||
PriceCalculationRequest calculationRequest = new PriceCalculationRequest();
|
||||
ProductItem productItem = new ProductItem();
|
||||
productItem.setProductType(ProductType.PHOTO_LOG);
|
||||
productItem.setProductId(template.getId().toString());
|
||||
productItem.setPurchaseCount(1);
|
||||
productItem.setScenicId(face.getScenicId().toString());
|
||||
calculationRequest.setProducts(Collections.singletonList(productItem));
|
||||
calculationRequest.setUserId(face.getMemberId());
|
||||
calculationRequest.setFaceId(face.getId());
|
||||
calculationRequest.setPreviewOnly(true); // 仅查询价格,不实际使用优惠
|
||||
PriceCalculationResult calculationResult = iPriceCalculationService.calculatePrice(calculationRequest);
|
||||
if (calculationResult.getFinalAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
sfpContent.setFreeCount(0);
|
||||
} else {
|
||||
sfpContent.setFreeCount(1);
|
||||
}
|
||||
contentList.add(1, sfpContent);
|
||||
}
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setScenicId(face.getScenicId());
|
||||
|
||||
@@ -916,15 +916,13 @@ public class OrderServiceImpl implements OrderService {
|
||||
List<OrderItemEntity> orderItems = goodsList.stream().map(goods -> {
|
||||
OrderItemEntity orderItem = new OrderItemEntity();
|
||||
orderItem.setOrderId(orderId);
|
||||
if (Long.valueOf(1L).equals(goods.getGoodsId())) {
|
||||
orderItem.setGoodsId(goods.getGoodsId());
|
||||
orderItem.setGoodsType(goods.getGoodsType());
|
||||
if (Integer.valueOf(1).equals(goods.getGoodsType())) {
|
||||
orderItem.setGoodsId(batchOrderReqVO.getFaceId());
|
||||
orderItem.setGoodsType(1);
|
||||
} else if (Long.valueOf(2L).equals(goods.getGoodsId())) {
|
||||
} else if (Integer.valueOf(2).equals(goods.getGoodsType())) {
|
||||
orderItem.setGoodsId(batchOrderReqVO.getFaceId());
|
||||
orderItem.setGoodsType(2);
|
||||
} else {
|
||||
// templateId
|
||||
orderItem.setGoodsId(goods.getGoodsId());
|
||||
} else if (Integer.valueOf(0).equals(goods.getGoodsType())) {
|
||||
orderItem.setGoodsType(-1);
|
||||
}
|
||||
return orderItem;
|
||||
|
||||
@@ -390,42 +390,51 @@ public class FaceMatchingOrchestrator {
|
||||
baseDynamicData.put("scenicText", scenicBasic.getName());
|
||||
baseDynamicData.put("dateStr", DateUtil.format(new Date(), "yyyy.MM.dd"));
|
||||
|
||||
// 遍历所有模板,逐个生成
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
for (PuzzleTemplateDTO template : templateList) {
|
||||
try {
|
||||
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName());
|
||||
// 使用虚拟线程池并行生成所有模板
|
||||
java.util.concurrent.atomic.AtomicInteger successCount = new java.util.concurrent.atomic.AtomicInteger(0);
|
||||
java.util.concurrent.atomic.AtomicInteger failCount = new java.util.concurrent.atomic.AtomicInteger(0);
|
||||
|
||||
// 构建生成请求
|
||||
PuzzleGenerateRequest generateRequest = new PuzzleGenerateRequest();
|
||||
generateRequest.setScenicId(scenicId);
|
||||
generateRequest.setUserId(memberId);
|
||||
generateRequest.setFaceId(faceId);
|
||||
generateRequest.setBusinessType("face_matching");
|
||||
generateRequest.setTemplateCode(template.getCode());
|
||||
generateRequest.setOutputFormat("PNG");
|
||||
generateRequest.setQuality(90);
|
||||
generateRequest.setDynamicData(new HashMap<>(baseDynamicData));
|
||||
generateRequest.setRequireRuleMatch(true);
|
||||
try (java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()) {
|
||||
// 为每个模板创建一个异步任务
|
||||
List<java.util.concurrent.CompletableFuture<Void>> futures = templateList.stream()
|
||||
.map(template -> java.util.concurrent.CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
log.info("开始生成拼图: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName());
|
||||
|
||||
// 调用拼图生成服务
|
||||
PuzzleGenerateResponse response = puzzleGenerateService.generate(generateRequest);
|
||||
// 构建生成请求
|
||||
PuzzleGenerateRequest generateRequest = new PuzzleGenerateRequest();
|
||||
generateRequest.setScenicId(scenicId);
|
||||
generateRequest.setUserId(memberId);
|
||||
generateRequest.setFaceId(faceId);
|
||||
generateRequest.setBusinessType("face_matching");
|
||||
generateRequest.setTemplateCode(template.getCode());
|
||||
generateRequest.setOutputFormat("PNG");
|
||||
generateRequest.setQuality(90);
|
||||
generateRequest.setDynamicData(new HashMap<>(baseDynamicData));
|
||||
generateRequest.setRequireRuleMatch(true);
|
||||
|
||||
log.info("拼图生成成功: scenicId={}, templateCode={}, imageUrl={}",
|
||||
scenicId, template.getCode(), response.getImageUrl());
|
||||
successCount++;
|
||||
// 调用拼图生成服务
|
||||
PuzzleGenerateResponse response = puzzleGenerateService.generate(generateRequest);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName(), e);
|
||||
failCount++;
|
||||
}
|
||||
log.info("拼图生成成功: scenicId={}, templateCode={}, imageUrl={}",
|
||||
scenicId, template.getCode(), response.getImageUrl());
|
||||
successCount.incrementAndGet();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("拼图生成失败: scenicId={}, templateCode={}, templateName={}",
|
||||
scenicId, template.getCode(), template.getName(), e);
|
||||
failCount.incrementAndGet();
|
||||
}
|
||||
}, executor))
|
||||
.toList();
|
||||
|
||||
// 等待所有任务完成
|
||||
java.util.concurrent.CompletableFuture.allOf(futures.toArray(new java.util.concurrent.CompletableFuture[0])).join();
|
||||
}
|
||||
|
||||
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
|
||||
scenicId, templateList.size(), successCount, failCount);
|
||||
log.info("景区拼图模板批量生成完成: scenicId={}, 总数={}, 成功={}, 失败={}",
|
||||
scenicId, templateList.size(), successCount.get(), failCount.get());
|
||||
|
||||
} catch (Exception e) {
|
||||
// 异步任务失败不影响主流程,仅记录日志
|
||||
|
||||
@@ -14,9 +14,7 @@ public interface TaskService {
|
||||
|
||||
TemplateRespVO workerGetTemplate(Long templateId, WorkerAuthReqVo req);
|
||||
|
||||
void createTaskByFaceIdAndTemplateId(Long faceId, Long templateId);
|
||||
|
||||
void createTaskByFaceIdAndTemplateId(Long faceId, Long templateId, int automatic);
|
||||
void createTaskByFaceIdAndTemplateId(Long faceId, Long templateId, boolean automatic);
|
||||
|
||||
void taskSuccess(Long taskId, TaskSuccessReqVo req);
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.ycwl.basic.mapper.TaskMapper;
|
||||
import com.ycwl.basic.mapper.VideoMapper;
|
||||
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
|
||||
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
|
||||
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
|
||||
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||
@@ -67,7 +66,6 @@ import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@@ -256,7 +254,7 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
|
||||
@Override
|
||||
public void forceCreateTaskByFaceIdAndTempalteId(Long faceId, Long templateId) {
|
||||
createTaskByFaceIdAndTemplateIdInternal(faceId, templateId, 0, true);
|
||||
createTaskByFaceIdAndTemplateIdInternal(faceId, templateId, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -304,34 +302,30 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
}
|
||||
if (Integer.valueOf(3).equals(scenicConfig.getInteger("book_routine")) || Integer.valueOf(4).equals(scenicConfig.getInteger("book_routine"))) {
|
||||
// 生成全部视频的逻辑
|
||||
templateList.forEach(template -> createTaskByFaceIdAndTemplateId(faceId, template.getId(), 1));
|
||||
templateList.forEach(template -> createTaskByFaceIdAndTemplateId(faceId, template.getId(), true));
|
||||
} else {
|
||||
if (Boolean.TRUE.equals(scenicConfig.getBoolean("force_create_vlog"))) {
|
||||
Long availableTemplateId = templateBiz.findFirstAvailableTemplate(templateList.stream().map(TemplateRespVO::getId).toList(), faceId, false);
|
||||
if (availableTemplateId != null) {
|
||||
createTaskByFaceIdAndTemplateId(faceId, availableTemplateId, 1);
|
||||
createTaskByFaceIdAndTemplateId(faceId, availableTemplateId, true);
|
||||
} else {
|
||||
log.info("faceId:{} available template is not exist", faceId);
|
||||
}
|
||||
} else {
|
||||
// 非强制创建,只创建第一个可用模板
|
||||
if (!templateList.isEmpty()) {
|
||||
createTaskByFaceIdAndTemplateId(faceId, templateList.getFirst().getId(), 1);
|
||||
createTaskByFaceIdAndTemplateId(faceId, templateList.getFirst().getId(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void createTaskByFaceIdAndTemplateId(Long faceId, Long templateId) {
|
||||
createTaskByFaceIdAndTemplateId(faceId, templateId, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTaskByFaceIdAndTemplateId(Long faceId, Long templateId, int automatic) {
|
||||
public void createTaskByFaceIdAndTemplateId(Long faceId, Long templateId, boolean automatic) {
|
||||
createTaskByFaceIdAndTemplateIdInternal(faceId, templateId, automatic, false);
|
||||
}
|
||||
|
||||
private void createTaskByFaceIdAndTemplateIdInternal(Long faceId, Long templateId, int automatic, boolean forceCreate) {
|
||||
private void createTaskByFaceIdAndTemplateIdInternal(Long faceId, Long templateId, boolean automatic, boolean forceCreate) {
|
||||
FaceEntity face = faceRepository.getFace(faceId);
|
||||
if (face == null) {
|
||||
log.info("faceId:{} is not exist", faceId);
|
||||
@@ -430,7 +424,7 @@ public class TaskTaskServiceImpl implements TaskService {
|
||||
taskEntity.setScenicId(face.getScenicId());
|
||||
taskEntity.setFaceId(faceId);
|
||||
taskEntity.setTemplateId(templateId);
|
||||
taskEntity.setAutomatic(automatic);
|
||||
taskEntity.setAutomatic(automatic ? 1 : 0);
|
||||
}
|
||||
taskEntity.setWorkerId(null);
|
||||
taskEntity.setStatus(0);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
server:
|
||||
port: 8030
|
||||
shutdown: graceful
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: zt
|
||||
lifecycle:
|
||||
timeout-per-shutdown-phase: 60s
|
||||
|
||||
# Feign配置(简化版,基于Nacos服务发现)
|
||||
feign:
|
||||
@@ -38,4 +41,7 @@ kafka:
|
||||
# 开发环境日志配置
|
||||
logging:
|
||||
level:
|
||||
com.ycwl.basic.integration.scenic.client: DEBUG
|
||||
com.ycwl.basic.integration.scenic.client: DEBUG
|
||||
|
||||
zhipu:
|
||||
api-key: a331e0fcf3f74518818b8e5129b79058.RXuUxUUjKdcxbF4L
|
||||
@@ -1,11 +1,17 @@
|
||||
server:
|
||||
port: 8031
|
||||
shutdown: graceful
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: zt
|
||||
lifecycle:
|
||||
timeout-per-shutdown-phase: 60s
|
||||
|
||||
# 生产环境日志级别
|
||||
logging:
|
||||
level:
|
||||
com.ycwl.basic.integration.scenic.client: WARN
|
||||
com.ycwl.basic.integration.scenic.client: WARN
|
||||
|
||||
zhipu:
|
||||
api-key: a331e0fcf3f74518818b8e5129b79058.RXuUxUUjKdcxbF4L
|
||||
@@ -112,8 +112,9 @@
|
||||
FROM source s
|
||||
),
|
||||
member_plog_data AS (
|
||||
SELECT 5 as type, gr.template_id as id, gr.result_image_url as url, gr.face_id
|
||||
SELECT 5 as type, gr.template_id as id, pt.scenic_id as scenic_id, gr.result_image_url as url, gr.face_id
|
||||
FROM puzzle_generation_record gr
|
||||
left join puzzle_template pt on gr.template_id = pt.id
|
||||
)
|
||||
SELECT
|
||||
oi.id AS oiId,
|
||||
@@ -168,7 +169,7 @@
|
||||
LEFT JOIN member_source_aicam_data msac ON o.face_id = msac.face_id AND oi.goods_id = msac.face_id AND oi.goods_type = 13
|
||||
LEFT JOIN member_photo_data mpd ON oi.goods_id = mpd.id AND mpd.type = oi.goods_type
|
||||
LEFT JOIN member_aio_photo_data mpa ON oi.goods_id = mpa.id AND mpa.type = oi.goods_type
|
||||
LEFT JOIN member_plog_data mpl ON oi.goods_id = mpl.id AND mpl.type = oi.goods_type AND o.face_id = mpl.face_id
|
||||
LEFT JOIN member_plog_data mpl ON (oi.goods_id = mpl.id OR oi.goods_id = mpl.scenic_id) AND mpl.type = oi.goods_type AND o.face_id = mpl.face_id
|
||||
WHERE oi.order_id = #{id};
|
||||
</select>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user