0元购逻辑,直接送

This commit is contained in:
Jerry Yan 2025-01-05 14:20:24 +08:00
parent 7befe07e70
commit 3907b5eb7a
19 changed files with 231 additions and 26 deletions

View File

@ -0,0 +1,93 @@
package com.ycwl.basic.biz;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.order.PriceObj;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
import com.ycwl.basic.model.pc.video.resp.VideoRespVO;
import com.ycwl.basic.repository.OrderRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.repository.TemplateRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class OrderBiz {
@Autowired
private VideoMapper videoMapper;
@Autowired
private ScenicRepository scenicRepository;
@Autowired
private TemplateRepository templateRepository;
@Autowired
private FaceMapper faceMapper;
@Autowired
private OrderRepository orderRepository;
public PriceObj queryPrice(int goodsType, Long goodsId) {
PriceObj priceObj = new PriceObj();
switch (goodsType) {
case 0: // video
VideoRespVO video = videoMapper.getById(goodsId);
if (video == null) {
return null;
}
priceObj.setGoodsId(goodsId);
priceObj.setGoodsType(goodsType);
TemplateRespVO template = templateRepository.getTemplate(video.getTemplateId());
if (template == null) {
return priceObj;
}
priceObj.setPrice(template.getPrice());
priceObj.setSlashPrice(template.getSlashPrice());
priceObj.setScenicId(video.getScenicId());
break;
case 1: // source
// goodsId 实际上是人脸ID
FaceRespVO _faceRespVO = faceMapper.getById(goodsId);
if (_faceRespVO == null || _faceRespVO.getScenicId() == null) {
return null;
}
ScenicEntity _scenic = scenicRepository.getScenic(_faceRespVO.getScenicId());
if (_scenic == null) {
return null;
}
priceObj.setPrice(_scenic.getPrice());
priceObj.setSlashPrice(_scenic.getPrice());
break;
case 2: // source
// goodsId 实际上是人脸ID
FaceRespVO __faceRespVO = faceMapper.getById(goodsId);
if (__faceRespVO == null || __faceRespVO.getScenicId() == null) {
return null;
}
ScenicEntity __scenic = scenicRepository.getScenic(__faceRespVO.getScenicId());
if (__scenic == null) {
return null;
}
priceObj.setPrice(__scenic.getPrice());
priceObj.setSlashPrice(__scenic.getPrice());
break;
}
return priceObj;
}
public IsBuyRespVO isBuy(Long userId, int goodsType, Long goodsId) {
IsBuyRespVO respVO = new IsBuyRespVO();
boolean isBuy = orderRepository.checkUserBuyItem(userId, goodsType, goodsId);
respVO.setBuy(isBuy);
if (!isBuy) {
PriceObj priceObj = queryPrice(goodsType, goodsId);
if (priceObj == null) {
return respVO;
}
respVO.setPrice(priceObj.getPrice());
respVO.setSlashPrice(priceObj.getSlashPrice());
}
return respVO;
}
}

View File

@ -56,12 +56,6 @@ public class AppGoodsController {
return goodsService.sourceGoodsInfo(worker.getUserId(), sourceId);
}
@ApiOperation("查询价格")
@PostMapping("/queryPrice")
public ApiResponse<BigDecimal> queryPrice(@RequestBody GoodsPriceQueryReq queryPriceData) {
return goodsService.queryPrice(queryPriceData);
}
/**
* 查询用户当前景区的视频合成任务状态
*
@ -86,11 +80,4 @@ public class AppGoodsController {
JwtInfo worker = JwtTokenUtil.getWorker();
return goodsService.getTaskStatusByTemplateId(worker.getUserId(), faceId, templateId);
}
@PostMapping("/submitVideoTask")
public ApiResponse<String> submitVideoTask(@RequestBody VideoTaskReq videoTaskReq) {
JwtInfo worker = JwtTokenUtil.getWorker();
taskService.createTaskByFaceIdAndTempalteId(videoTaskReq.getFaceId(),videoTaskReq.getTemplateId(),0);
return ApiResponse.success("成功");
}
}

View File

@ -1,12 +1,17 @@
package com.ycwl.basic.controller.mobile;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.model.mobile.goods.GoodsPriceQueryReq;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.mobile.order.OrderAppPageReq;
import com.ycwl.basic.model.mobile.order.RefundOrderReq;
import com.ycwl.basic.model.pc.order.req.OrderAddReq;
import com.ycwl.basic.model.pc.order.resp.OrderAppRespVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.repository.OrderRepository;
import com.ycwl.basic.service.mobile.GoodsService;
import com.ycwl.basic.service.pc.OrderService;
import com.ycwl.basic.utils.ApiResponse;
import io.swagger.annotations.Api;
@ -25,6 +30,10 @@ public class AppOrderController {
@Autowired
private OrderService orderService;
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderBiz orderBiz;
@ApiOperation("用户端订单列表查询")
@PostMapping("/page")
@ -61,4 +70,9 @@ public class AppOrderController {
return orderService.refundOrder(refundOrderReq);
}
@GetMapping("/scenic/{scenicId}/query")
public ApiResponse<IsBuyRespVO> isBuy(@PathVariable("scenicId") Long scenicId, @RequestParam("type") Integer type, @RequestParam("goodsId") Long goodsId) {
Long userId = Long.parseLong(BaseContextHandler.getUserId());
return ApiResponse.success(orderBiz.isBuy(userId, type, goodsId));
}
}

View File

@ -3,6 +3,7 @@ package com.ycwl.basic.mapper;
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicAddOrUpdateReq;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
@ -20,6 +21,8 @@ import java.util.List;
public interface ScenicMapper {
List<ScenicRespVO> list(ScenicReqQuery scenicReqQuery);
ScenicEntity get(Long id);
ScenicRespVO getById(Long id);
int add(ScenicAddOrUpdateReq scenic);

View File

@ -41,5 +41,5 @@ public interface VideoMapper {
MemberVideoEntity queryUserVideo(Long userId, Long videoId);
int updateRelationWhenTaskSuccess(Long taskId, Long videoId);
int updateRelationWhenTaskSuccess(Long taskId, Long videoId, int isBuy);
}

View File

@ -15,8 +15,8 @@ import lombok.experimental.Accessors;
public class GoodsPriceQueryReq {
@ApiModelProperty("景区id")
private Long scenicId;
@ApiModelProperty("商品类型 1:成片vlog 2:源素材")
@ApiModelProperty("商品类型 0:成片vlog 12:源素材")
private Integer goodsType;
@ApiModelProperty("商品id goodsType=1时才有值")
@ApiModelProperty("商品id goodsType=0时才有值")
private Long goodsId;
}

View File

@ -0,0 +1,15 @@
package com.ycwl.basic.model.mobile.order;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class IsBuyRespVO {
private boolean isBuy;
private Long orderId;
private int goodsType;
private Long goodsId;
private BigDecimal price;
private BigDecimal slashPrice;
}

View File

@ -0,0 +1,14 @@
package com.ycwl.basic.model.mobile.order;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class PriceObj {
private Long scenicId;
private int goodsType;
private Long goodsId;
private BigDecimal price = BigDecimal.ZERO;
private BigDecimal slashPrice;
}

View File

@ -6,6 +6,7 @@ import lombok.Data;
public class MatchLocalRecord {
private Long faceSampleId;
private String faceUrl;
private Float score;
private Float confidence;
private String idStr;
}

View File

@ -23,7 +23,7 @@ public class OrderEntity {
/**
* 微信openId
*/
private Long openId;
private String openId;
/**
* 价格
*/

View File

@ -38,4 +38,8 @@ public class OrderRepository {
public boolean checkUserBuyVideo(Long userId, Long videoId) {
return checkUserBuyItem(userId, 0, videoId);
}
public void clearUserBuyItemCache(Long userId, int goodsType, Long goodsId) {
redisTemplate.delete(String.format(ORDER_ITEM_CACHE_KEY, userId, goodsType, goodsId));
}
}

View File

@ -1,4 +1,47 @@
package com.ycwl.basic.repository;
import com.alibaba.fastjson.JSONObject;
import com.ycwl.basic.mapper.ScenicMapper;
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class ScenicRepository {
@Autowired
private ScenicMapper scenicMapper;
@Autowired
private RedisTemplate<String, String> redisTemplate;
public static final String SCENIC_CACHE_KEY = "scenic:%s";
public static final String SCENIC_CONFIG_CACHE_KEY = "scenic:%s:config";
public ScenicEntity getScenic(Long id) {
if (redisTemplate.hasKey(String.format(SCENIC_CACHE_KEY, id))) {
return JSONObject.parseObject(redisTemplate.opsForValue().get(String.format(SCENIC_CACHE_KEY, id)), ScenicEntity.class);
}
ScenicEntity scenic = scenicMapper.get(id);
if (scenic != null) {
redisTemplate.opsForValue().set(String.format(SCENIC_CACHE_KEY, id), JSONObject.toJSONString(scenic));
}
return scenic;
}
public ScenicConfigEntity getScenicConfig(Long scenicId) {
if (redisTemplate.hasKey(String.format(SCENIC_CONFIG_CACHE_KEY, scenicId))) {
return JSONObject.parseObject(redisTemplate.opsForValue().get(String.format(SCENIC_CONFIG_CACHE_KEY, scenicId)), ScenicConfigEntity.class);
}
ScenicConfigEntity scenicConfig = scenicMapper.getConfig(scenicId);
if (scenicConfig != null) {
redisTemplate.opsForValue().set(String.format(SCENIC_CONFIG_CACHE_KEY, scenicId), JSONObject.toJSONString(scenicConfig));
}
return scenicConfig;
}
public void clearCache(Long scenicId) {
redisTemplate.delete(String.format(SCENIC_CACHE_KEY, scenicId));
redisTemplate.delete(String.format(SCENIC_CONFIG_CACHE_KEY, scenicId));
}
}

View File

@ -41,6 +41,7 @@ import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.model.wx.WxPayRespVO;
import com.ycwl.basic.model.wx.WxchatCallbackSuccessData;
import com.ycwl.basic.repository.OrderRepository;
import com.ycwl.basic.service.HttpService;
import com.ycwl.basic.service.mobile.WxPayService;
import com.ycwl.basic.service.pc.OrderService;
@ -100,6 +101,8 @@ public class WxPayServiceImpl implements WxPayService {
private SourceMapper sourceMapper;
@Autowired
private VideoMapper videoMapper;
@Autowired
private OrderRepository orderRepository;
@Override
public WxPayRespVO createOrder(WXPayOrderReqVO req) {
@ -211,6 +214,7 @@ public class WxPayServiceImpl implements WxPayService {
OrderRespVO byId = orderMapper.getById(orderId);
List<OrderItemEntity> orderItemList = orderMapper.listOrderItemByOrderId(orderId);
orderItemList.forEach(orderItemVO -> {
orderRepository.clearUserBuyItemCache(byId.getMemberId(), orderItemVO.getGoodsType(), orderItemVO.getGoodsId());
switch (orderItemVO.getGoodsType()) {
case 0: // 成片
MemberVideoEntity memberVideoEntity = new MemberVideoEntity();
@ -224,7 +228,8 @@ public class WxPayServiceImpl implements WxPayService {
case 2: // 源素材
MemberSourceEntity memberSourceEntity = new MemberSourceEntity();
memberSourceEntity.setMemberId(byId.getMemberId());
memberSourceEntity.setSourceId(orderItemVO.getGoodsId());
// 源素材的goodsId是人脸ID
memberSourceEntity.setFaceId(orderItemVO.getGoodsId());
memberSourceEntity.setType(orderItemVO.getGoodsType());
memberSourceEntity.setIsBuy(1);
memberSourceEntity.setOrderId(orderId);

View File

@ -133,16 +133,17 @@ public class TaskFaceServiceImpl implements TaskFaceService {
} else {
record.setFaceUrl(getFaceUrl(record.getFaceSampleId()));
}
record.setScore(item.getScore());
record.setConfidence(item.getConfidence());
return record;
})
.collect(Collectors.toList());
log.matchLocalRecord(records);
List<Long> faceSampleIds = records.stream()
.filter(record -> record.getConfidence() > 60)
.filter(record -> record.getScore() > 0.6)
.map(MatchLocalRecord::getFaceSampleId)
.collect(Collectors.toList());
respVo.setFirstMatchRate(matchList.get(0).getFaceItems().get(0).getConfidence());
respVo.setFirstMatchRate(matchList.get(0).getFaceItems().get(0).getScore());
respVo.setSampleListIds(faceSampleIds);
return respVo;
} catch (Exception e) {

View File

@ -1,6 +1,7 @@
package com.ycwl.basic.service.impl.task;
import com.alibaba.fastjson.JSON;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.constant.TaskConstant;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
@ -9,6 +10,7 @@ import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.mapper.TaskMapper;
import com.ycwl.basic.mapper.TemplateMapper;
import com.ycwl.basic.mapper.VideoMapper;
import com.ycwl.basic.model.mobile.order.PriceObj;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
@ -71,6 +73,8 @@ public class TaskTaskServiceImpl implements TaskService {
private TemplateRepository templateRepository;
@Autowired
private VideoTaskRepository videoTaskRepository;
@Autowired
private OrderBiz orderBiz;
private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
String accessKey = req.getAccessKey();
@ -127,6 +131,10 @@ public class TaskTaskServiceImpl implements TaskService {
if (faceId == null) {
return;
}
boolean canGenerate = templateRepository.determineTemplateCanGenerate(templateId, faceId);
if (!canGenerate) {
return;
}
TemplateConfigEntity config = templateRepository.getTemplateConfig(templateId);
FaceRespVO faceRespVO = faceMapper.getById(faceId);
if (faceRespVO == null) {
@ -237,6 +245,10 @@ public class TaskTaskServiceImpl implements TaskService {
task.faceSampleId = faceSampleIds;
task.memberId = faceRespVO.getMemberId();
task.callback = () -> {
boolean canGenerate = templateRepository.determineTemplateCanGenerate(templateId, faceId);
if (!canGenerate) {
return;
}
List<SourceEntity> videoSourceList = sourceMapper.listVideoByFaceRelation(faceId);
Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
.peek(item -> item.setUrl(item.getVideoUrl()))
@ -268,6 +280,10 @@ public class TaskTaskServiceImpl implements TaskService {
memberVideoEntity.setTaskId(list.get(0).getId());
VideoEntity video = videoMapper.findByTaskId(list.get(0).getId());
if (video != null) {
PriceObj priceObj = orderBiz.queryPrice(0, video.getId());
if (priceObj.getPrice().equals(BigDecimal.ZERO)) {
memberVideoEntity.setIsBuy(1);
}
memberVideoEntity.setVideoId(video.getId());
}
}
@ -296,7 +312,6 @@ public class TaskTaskServiceImpl implements TaskService {
if (video != null) {
video.setVideoUrl(task.getVideoUrl());
videoMapper.update(video);
videoMapper.updateRelationWhenTaskSuccess(taskId, video.getId());
} else {
video = new VideoEntity();
video.setId(SnowFlakeUtil.getLongId());
@ -307,8 +322,13 @@ public class TaskTaskServiceImpl implements TaskService {
video.setVideoUrl(task.getVideoUrl());
video.setCreateTime(new Date());
videoMapper.add(video);
videoMapper.updateRelationWhenTaskSuccess(taskId, video.getId());
}
int isBuy = 0;
PriceObj priceObj = orderBiz.queryPrice(0, video.getId());
if (priceObj.getPrice().equals(BigDecimal.ZERO)) {
isBuy = 1;
}
videoMapper.updateRelationWhenTaskSuccess(taskId, video.getId(), isBuy);
}
@Override

View File

@ -93,8 +93,8 @@
END AS goods_name,
CASE oi.goods_type
WHEN '0' THEN mvd.face_id
WHEN '1' THEN msd.face_id
WHEN '2' THEN msd.face_id
WHEN '1' THEN oi.goods_id
WHEN '2' THEN oi.goods_id
END AS face_id,
CASE oi.goods_type
WHEN '0' THEN mvd.video_url

View File

@ -187,6 +187,11 @@
from scenic_config
where scenic_id = #{scenicId}
</select>
<select id="get" resultType="com.ycwl.basic.model.pc.scenic.entity.ScenicEntity">
select *
from scenic
where id = #{id}
</select>
<resultMap id="scenic" type="com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO">
<id property="id" column="id"/>

View File

@ -36,7 +36,7 @@
<if test="isBuy!=null">is_buy = #{isBuy}, </if>
<if test="orderId!=null">order_id = #{orderId}, </if>
</set>
where member_id = #{memberId} and source_id = #{sourceId} and type = #{type}
where member_id = #{memberId} and face_id = #{faceId} and type = #{type}
</update>
<delete id="deleteById">
delete from source where id = #{id}

View File

@ -39,7 +39,7 @@
</update>
<update id="updateRelationWhenTaskSuccess">
update member_video
set video_id = #{videoId}
set video_id = #{videoId}, is_buy = #{isBuy}
where task_id = #{taskId}
</update>
<delete id="deleteById">