buyer-api/src/main/java/cn/lili/controller/goods/GoodsBuyerController.java
@@ -1,5 +1,6 @@ package cn.lili.controller.goods; import cn.lili.base.Result; import cn.lili.common.enums.ResultCode; import cn.lili.common.enums.ResultUtil; import cn.lili.common.exception.ServiceException; @@ -11,6 +12,7 @@ import cn.lili.modules.goods.entity.vos.GoodsVO; import cn.lili.modules.goods.service.GoodsService; import cn.lili.modules.goods.service.GoodsSkuService; import cn.lili.modules.lmk.domain.query.VideoGoodsEsQuery; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.entity.dos.EsGoodsRelatedInfo; import cn.lili.modules.search.entity.dto.EsGoodsSearchDTO; @@ -115,6 +117,12 @@ return ResultUtil.data(goodsSearchService.searchGoodsByPage(goodsSearchParams, pageVO)); } @ApiOperation(value = "商品分页-发布视频时关联商品") @GetMapping("/video/es") public Result videoGoodsEsPage(VideoGoodsEsQuery query) { return goodsSearchService.videoGoodsEsPage(query); } @ApiOperation(value = "从ES中获取相关商品品牌名称,分类名称及属性") @GetMapping("/es/related") public ResultMessage<EsGoodsRelatedInfo> getGoodsRelatedByPageFromEs(EsGoodsSearchDTO goodsSearchParams, PageVO pageVO) { framework/src/main/java/cn/lili/modules/lmk/domain/entity/VideoGoods.java
New file @@ -0,0 +1,45 @@ package cn.lili.modules.lmk.domain.entity; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 视频商品中间表 * * @author xp * @since 2025-06-15 */ @Data @TableName("lmk_video_goods") public class VideoGoods { private static final long serialVersionUID = 1L; @TableId @ApiModelProperty(value = "唯一标识", hidden = true) private String id; @TableField("video_id") /** 视频id */ private String videoId; @TableField("goods_id") /** 商品id */ private String goodsId; @TableField("order_num") /** 排序 */ private Integer orderNum; @TableField("goods_num") /** 商品数量 */ private Integer goodsNum; @TableField(fill = FieldFill.INSERT) @ApiModelProperty(value = "删除标志 true/false 删除/未删除", hidden = true) private Boolean deleteFlag; } framework/src/main/java/cn/lili/modules/lmk/domain/form/WxVideoForm.java
@@ -4,6 +4,8 @@ import cn.lili.group.Add; import cn.lili.base.AbsForm; import cn.lili.modules.lmk.domain.entity.Video; import cn.lili.modules.lmk.domain.vo.VideoGoodsPublishVO; import cn.lili.modules.lmk.domain.vo.VideoGoodsVO; import org.hibernate.validator.constraints.Length; import org.springframework.beans.BeanUtils; @@ -53,8 +55,8 @@ private List<WxVideoTagForm> tags = new ArrayList<>(2); // @NotBlank(message = "商品id不能为空", groups = {Add.class, Update.class}) @ApiModelProperty("商品id") private String goodsId; @ApiModelProperty("商品列表") private List<VideoGoodsPublishVO> goodsList; @ApiModelProperty("视频填充模式") private String videoFit; framework/src/main/java/cn/lili/modules/lmk/domain/query/VideoGoodsEsQuery.java
New file @@ -0,0 +1,28 @@ package cn.lili.modules.lmk.domain.query; import cn.lili.base.AbsQuery; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 发布视频时,关联商品的查询 * * @author:xp * @date:2025/6/13 10:04 */ @Data @ApiModel("发布视频时,关联商品的查询") public class VideoGoodsEsQuery { @ApiModelProperty("搜索关键词") private String keyword; @ApiModelProperty("查自家店铺的商品") private Boolean searchFromSelfStore; private int pageNumber; private int pageSize; } framework/src/main/java/cn/lili/modules/lmk/domain/vo/VideoGoodsPublishVO.java
New file @@ -0,0 +1,21 @@ package cn.lili.modules.lmk.domain.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * @author:xp * @date:2025/6/15 19:10 */ @Data @ApiModel("发布视频-商品信息") public class VideoGoodsPublishVO { @ApiModelProperty("商品id") private String goodsId; @ApiModelProperty("商品数量") private Integer goodsNum; } framework/src/main/java/cn/lili/modules/lmk/mapper/VideoGoodsMapper.java
New file @@ -0,0 +1,17 @@ package cn.lili.modules.lmk.mapper; import cn.lili.modules.lmk.domain.entity.VideoGoods; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; /** * 视频商品中间表 Mapper 接口 * * @author xp * @since 2025-06-15 */ @Mapper public interface VideoGoodsMapper extends BaseMapper<VideoGoods> { } framework/src/main/java/cn/lili/modules/lmk/service/VideoGoodsService.java
New file @@ -0,0 +1,14 @@ package cn.lili.modules.lmk.service; import cn.lili.modules.lmk.domain.entity.VideoGoods; import com.baomidou.mybatisplus.extension.service.IService; /** * 视频商品中间表 服务类 * * @author xp * @since 2025-06-15 */ public interface VideoGoodsService extends IService<VideoGoods> { } framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoGoodsServiceImpl.java
New file @@ -0,0 +1,22 @@ package cn.lili.modules.lmk.service.impl; import cn.lili.modules.lmk.domain.entity.VideoGoods; import cn.lili.modules.lmk.mapper.VideoGoodsMapper; import cn.lili.modules.lmk.service.VideoGoodsService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; /** * 视频商品中间表 服务实现类 * * @author xp * @since 2025-06-15 */ @Service @RequiredArgsConstructor public class VideoGoodsServiceImpl extends ServiceImpl<VideoGoodsMapper, VideoGoods> implements VideoGoodsService { private final VideoGoodsMapper videoGoodsMapper; } framework/src/main/java/cn/lili/modules/lmk/service/impl/VideoServiceImpl.java
@@ -55,6 +55,7 @@ private final MySubscribeService mySubscribeService; private final MemberService memberService; private final VideoAccountService videoAccountService; private final VideoGoodsService videoGoodsService; /** @@ -187,8 +188,21 @@ return videoTagRef; }).collect(Collectors.toList()); videoTagRefService.saveBatch(videoTagRefs); // 3.保存视频文件信息 // 3. 保存视频文件信息 lmkFileService.addByForm(form.getFileInfo()); // 4. 处理选择的商品 if (CollectionUtils.isNotEmpty(form.getGoodsList())) { List<VideoGoods> videoGoods = new ArrayList<>(2); for (int i = 0; i < form.getGoodsList().size(); i++) { VideoGoods e = new VideoGoods(); e.setVideoId(video.getId()); e.setGoodsId(form.getGoodsList().get(i).getGoodsId()); e.setGoodsNum(form.getGoodsList().get(i).getGoodsNum()); e.setOrderNum(i); videoGoods.add(e); } videoGoodsService.saveBatch(videoGoods); } return Result.ok("发布成功,视频审核中~"); } framework/src/main/java/cn/lili/modules/search/service/EsGoodsSearchService.java
@@ -1,6 +1,8 @@ package cn.lili.modules.search.service; import cn.lili.base.Result; import cn.lili.common.vo.PageVO; import cn.lili.modules.lmk.domain.query.VideoGoodsEsQuery; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.entity.dos.EsGoodsRelatedInfo; import cn.lili.modules.search.entity.dto.EsGoodsSearchDTO; @@ -59,4 +61,12 @@ * @return 商品索引 */ EsGoodsIndex getEsGoodsById(String id); /** * 商品分页,发布视频时关联商品的查询 * * @param query * @return */ Result videoGoodsEsPage(VideoGoodsEsQuery query); } framework/src/main/java/cn/lili/modules/search/serviceimpl/EsGoodsSearchServiceImpl.java
@@ -3,12 +3,15 @@ import cn.hutool.core.convert.Convert; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ArrayUtil; import cn.lili.base.Result; import cn.lili.cache.Cache; import cn.lili.cache.CachePrefix; import cn.lili.common.exception.ServiceException; import cn.lili.common.security.context.UserContext; import cn.lili.common.vo.PageVO; import cn.lili.modules.goods.entity.enums.GoodsAuthEnum; import cn.lili.modules.goods.entity.enums.GoodsStatusEnum; import cn.lili.modules.lmk.domain.query.VideoGoodsEsQuery; import cn.lili.modules.search.entity.dos.EsGoodsIndex; import cn.lili.modules.search.entity.dos.EsGoodsRelatedInfo; import cn.lili.modules.search.entity.dto.EsGoodsSearchDTO; @@ -29,6 +32,7 @@ import org.elasticsearch.index.query.functionscore.FieldValueFactorFunctionBuilder; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders; import org.elasticsearch.index.search.MultiMatchQuery; import org.elasticsearch.search.aggregations.*; import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested; import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms; @@ -38,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.core.*; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; @@ -176,6 +181,38 @@ return this.restTemplate.get(id, EsGoodsIndex.class); } @Override public Result videoGoodsEsPage(VideoGoodsEsQuery q) { // 判断商品索引是否存在 if (!restTemplate.indexOps(EsGoodsIndex.class).exists()) { return Result.ok(); } // 根据销量倒序排列 Pageable pageable = PageRequest.of(q.getPageNumber(), q.getPageSize(), Sort.by("buyCount").descending()); NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); queryBuilder.withPageable(pageable); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 关键词匹配商品名称、商品编号 if (!StringUtils.isEmpty(q.getKeyword())) { boolQuery.must(QueryBuilders.multiMatchQuery(q.getKeyword(), "goodsName", "sn")); } if (q.getSearchFromSelfStore()) { // 如果只查自家店铺商品 boolQuery.must(QueryBuilders.termQuery("storeId", UserContext.getCurrentUser().getStoreId())); } queryBuilder.withQuery(boolQuery); NativeSearchQuery query = queryBuilder.build(); SearchHits<EsGoodsIndex> searchHits = restTemplate.search(query, EsGoodsIndex.class); List<EsGoodsIndex> data = searchHits.stream().map(hit -> hit.getContent()).collect(Collectors.toList()); return Result.ok().data(data).total(searchHits.getTotalHits()); } /** * 转换搜索结果为聚合商品展示信息 * framework/src/main/resources/mapper/lmk/VideoGoodsMapper.xml
New file @@ -0,0 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.lili.modules.lmk.mapper.VideoGoodsMapper"> </mapper>