You've already forked FrameTour-BE
feat(service): 优化商品查询逻辑并新增分组查询接口
- 在 SourceMapper 中新增 queryGroupedByFaceAndType 方法,支持按 faceId 和 type 分组查询 - 调整 orderBiz.isBuy 方法的参数顺序,统一调用格式 - 修改 GoodsServiceImpl 中源素材查询逻辑,使用新分组方法减少循环嵌套 - 简化源素材去重及过滤禁用类型的处理流程 - 提前获取景区配置信息,避免重复查询 - 优化代码结构,提升可读性和维护性
This commit is contained in:
@@ -67,6 +67,13 @@ public interface SourceMapper {
|
||||
|
||||
List<SourceRespVO> queryByRelation(SourceReqQuery sourceReqQuery);
|
||||
|
||||
/**
|
||||
* 按 faceId 和 type 分组查询源素材,每组返回最新的一条记录
|
||||
* @param sourceReqQuery 查询参数
|
||||
* @return 分组后的素材列表
|
||||
*/
|
||||
List<SourceRespVO> queryGroupedByFaceAndType(SourceReqQuery sourceReqQuery);
|
||||
|
||||
SourceEntity querySameVideo(Long faceSampleId, Long deviceId);
|
||||
|
||||
int hasRelationTo(Long memberId, Long sourceId, int type);
|
||||
|
||||
@@ -310,7 +310,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsDetailVO.setFaceId(entity.getFaceId());
|
||||
goodsDetailVO.setIsBuy(entity.getIsBuy());
|
||||
if (Integer.valueOf(0).equals(entity.getIsBuy())) {
|
||||
IsBuyRespVO buy = orderBiz.isBuy(userId, videoRespVO.getScenicId(), 0, videoId);
|
||||
IsBuyRespVO buy = orderBiz.isBuy(videoRespVO.getScenicId(), userId, entity.getFaceId(), 0, videoId);
|
||||
if (!buy.isBuy()) {
|
||||
PriceObj priceObj = orderBiz.queryPrice(videoRespVO.getScenicId(), 0, videoId);
|
||||
if (priceObj.isFree()) {
|
||||
@@ -584,7 +584,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsUrlVO.setCreateTime(source.getCreateTime());
|
||||
return goodsUrlVO;
|
||||
}).collect(Collectors.toList());
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), query.getSourceType(), face.getId());
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), query.getSourceType(), face.getId());
|
||||
if (!isBuy.isBuy()) {
|
||||
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
|
||||
if (scenicConfig != null && ((scenicConfig.getAntiScreenRecordType() & 2) == 0)) {
|
||||
@@ -676,7 +676,7 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
}
|
||||
return true;
|
||||
}).count();
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getMemberId(), face.getScenicId(), query.getSourceType(), face.getId());
|
||||
IsBuyRespVO isBuy = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), face.getId(), query.getSourceType(), face.getId());
|
||||
if (count > 0) {
|
||||
if (!isBuy.isBuy()) {
|
||||
return Collections.emptyList();
|
||||
@@ -842,17 +842,14 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
return ApiResponse.success(Collections.emptyList());
|
||||
}
|
||||
|
||||
// 获取景区配置
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
|
||||
// 使用 LinkedHashMap 按 goodsType-goodsId 去重
|
||||
Map<String, GoodsPageVO> goodsMap = new LinkedHashMap<>();
|
||||
|
||||
// 循环查询每个 faceId 的商品
|
||||
for (Long faceId : faceIds) {
|
||||
// 构造查询参数
|
||||
GoodsReqQuery query = new GoodsReqQuery();
|
||||
query.setFaceId(faceId);
|
||||
query.setIsBuy(isBuy);
|
||||
query.setScenicId(scenicId);
|
||||
|
||||
// 查询成片 vlog (goodsType = 0)
|
||||
VideoReqQuery videoReqQuery = new VideoReqQuery();
|
||||
videoReqQuery.setScenicId(scenicId);
|
||||
@@ -880,55 +877,52 @@ public class GoodsServiceImpl implements GoodsService {
|
||||
goodsMap.put(key, goodsPageVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询源素材 (goodsType = 1/2)
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setScenicId(scenicId);
|
||||
sourceReqQuery.setIsBuy(isBuy);
|
||||
sourceReqQuery.setFaceId(faceId);
|
||||
// 查询源素材 (goodsType = 1/2) - 使用新的 GROUP BY 方法
|
||||
SourceReqQuery sourceReqQuery = new SourceReqQuery();
|
||||
sourceReqQuery.setScenicId(scenicId);
|
||||
sourceReqQuery.setIsBuy(isBuy);
|
||||
sourceReqQuery.setFaceIds(faceIds);
|
||||
|
||||
List<SourceRespVO> sourceList = sourceMapper.queryByRelation(sourceReqQuery);
|
||||
ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
|
||||
// 使用 queryGroupedByFaceAndType 方法,数据库已经按 faceId+type 分组
|
||||
List<SourceRespVO> sourceList = sourceMapper.queryGroupedByFaceAndType(sourceReqQuery);
|
||||
|
||||
// 按 faceId 和 type 分组处理
|
||||
sourceList.stream()
|
||||
.collect(Collectors.groupingBy(SourceRespVO::getFaceId))
|
||||
.forEach((sourceFaceId, goods) -> {
|
||||
goods.stream()
|
||||
.collect(Collectors.groupingBy(SourceRespVO::getType))
|
||||
.forEach((type, sourcesByType) -> {
|
||||
// 根据景区配置过滤禁用的素材类型
|
||||
boolean isDisabled = false;
|
||||
if (Integer.valueOf(1).equals(type)) {
|
||||
isDisabled = Boolean.TRUE.equals(scenicConfig.getBoolean("disable_source_video"));
|
||||
} else if (Integer.valueOf(2).equals(type)) {
|
||||
isDisabled = Boolean.TRUE.equals(scenicConfig.getBoolean("disable_source_image"));
|
||||
}
|
||||
// 遍历分组后的结果,每个 faceId+type 组合只有一条记录
|
||||
for (SourceRespVO source : sourceList) {
|
||||
Integer type = source.getType();
|
||||
Long sourceFaceId = source.getFaceId();
|
||||
|
||||
if (!isDisabled) {
|
||||
String key = type + "-" + sourceFaceId; // goodsType=type, goodsId=faceId(源素材用faceId作为ID)
|
||||
if (!goodsMap.containsKey(key)) {
|
||||
GoodsPageVO goodsPageVO = new GoodsPageVO();
|
||||
goodsPageVO.setFaceId(sourceFaceId);
|
||||
goodsPageVO.setGoodsType(type);
|
||||
if (type == 1) {
|
||||
goodsPageVO.setGoodsName("录像集");
|
||||
goodsPageVO.setTemplateCoverUrl(scenicConfig.getString("video_cover_url"));
|
||||
} else if (type == 2) {
|
||||
goodsPageVO.setGoodsName("照片集");
|
||||
goodsPageVO.setTemplateCoverUrl(scenicConfig.getString("photo_cover_url"));
|
||||
} else {
|
||||
goodsPageVO.setGoodsName("未知商品");
|
||||
}
|
||||
if (StringUtils.isBlank(goodsPageVO.getTemplateCoverUrl())) {
|
||||
goodsPageVO.setTemplateCoverUrl(sourcesByType.getFirst().getUrl());
|
||||
}
|
||||
goodsPageVO.setScenicId(scenicId);
|
||||
goodsMap.put(key, goodsPageVO);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
// 根据景区配置过滤禁用的素材类型
|
||||
boolean isDisabled = false;
|
||||
if (Integer.valueOf(1).equals(type)) {
|
||||
isDisabled = Boolean.TRUE.equals(scenicConfig.getBoolean("disable_source_video"));
|
||||
} else if (Integer.valueOf(2).equals(type)) {
|
||||
isDisabled = Boolean.TRUE.equals(scenicConfig.getBoolean("disable_source_image"));
|
||||
}
|
||||
|
||||
if (!isDisabled) {
|
||||
String key = type + "-" + sourceFaceId; // goodsType=type, goodsId=faceId(源素材用faceId作为ID)
|
||||
if (!goodsMap.containsKey(key)) {
|
||||
GoodsPageVO goodsPageVO = new GoodsPageVO();
|
||||
goodsPageVO.setFaceId(sourceFaceId);
|
||||
goodsPageVO.setGoodsType(type);
|
||||
if (type == 1) {
|
||||
goodsPageVO.setGoodsName("录像集");
|
||||
goodsPageVO.setTemplateCoverUrl(scenicConfig.getString("video_cover_url"));
|
||||
} else if (type == 2) {
|
||||
goodsPageVO.setGoodsName("照片集");
|
||||
goodsPageVO.setTemplateCoverUrl(scenicConfig.getString("photo_cover_url"));
|
||||
} else {
|
||||
goodsPageVO.setGoodsName("未知商品");
|
||||
}
|
||||
if (StringUtils.isBlank(goodsPageVO.getTemplateCoverUrl())) {
|
||||
goodsPageVO.setTemplateCoverUrl(source.getUrl());
|
||||
}
|
||||
goodsPageVO.setScenicId(scenicId);
|
||||
goodsMap.put(key, goodsPageVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回去重后的商品列表
|
||||
|
||||
@@ -265,15 +265,58 @@
|
||||
select so.id, ms.face_id, ms.scenic_id, ms.type, so.thumb_url, so.url, ms.is_free, so.create_time, so.update_time,ms.is_buy
|
||||
from member_source ms
|
||||
left join source so on ms.source_id = so.id
|
||||
|
||||
|
||||
where
|
||||
ms.member_id = #{memberId} and so.id
|
||||
ms.member_id = #{memberId} and so.id is not null
|
||||
<if test="faceId!= null">and ms.face_id = #{faceId} </if>
|
||||
<if test="type!=null">and ms.type = #{type} </if>
|
||||
<if test="scenicId!= null">and ms.scenic_id = #{scenicId} </if>
|
||||
<if test="isBuy!=null">and ms.is_buy = #{isBuy}</if>
|
||||
order by so.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="queryGroupedByFaceAndType" resultType="com.ycwl.basic.model.pc.source.resp.SourceRespVO">
|
||||
SELECT
|
||||
t.id,
|
||||
t.face_id,
|
||||
t.scenic_id,
|
||||
t.type,
|
||||
t.thumb_url,
|
||||
t.url,
|
||||
t.is_free,
|
||||
t.create_time,
|
||||
t.update_time,
|
||||
t.is_buy
|
||||
FROM (
|
||||
SELECT
|
||||
so.id,
|
||||
ms.face_id,
|
||||
ms.scenic_id,
|
||||
ms.type,
|
||||
so.thumb_url,
|
||||
so.url,
|
||||
ms.is_free,
|
||||
so.create_time,
|
||||
so.update_time,
|
||||
ms.is_buy,
|
||||
ROW_NUMBER() OVER (PARTITION BY ms.face_id, ms.type ORDER BY so.create_time DESC) as rn
|
||||
FROM member_source ms
|
||||
LEFT JOIN source so ON ms.source_id = so.id
|
||||
WHERE so.id IS NOT NULL
|
||||
<if test="faceIds != null and faceIds.size() > 0">
|
||||
AND ms.face_id IN
|
||||
<foreach collection="faceIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="faceId != null">AND ms.face_id = #{faceId}</if>
|
||||
<if test="scenicId != null">AND ms.scenic_id = #{scenicId}</if>
|
||||
<if test="isBuy != null">AND ms.is_buy = #{isBuy}</if>
|
||||
) t
|
||||
WHERE t.rn = 1
|
||||
ORDER BY t.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="querySameVideo" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
|
||||
select *
|
||||
from source
|
||||
|
||||
Reference in New Issue
Block a user