master:新增商品时传输数据到ES;
parent
a2cc166908
commit
2c69535ed5
|
|
@ -22,6 +22,7 @@ import org.springframework.validation.annotation.Validated;
|
|||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -84,33 +85,33 @@ public class StoreProductController extends XktBaseController {
|
|||
/**
|
||||
* 新增档口商品
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:product:add')")
|
||||
// @PreAuthorize("@ss.hasPermi('system:product:add')")
|
||||
@Log(title = "档口商品", businessType = BusinessType.INSERT)
|
||||
@ApiOperation(value = "新增档口商品", httpMethod = "POST", response = R.class)
|
||||
@PostMapping
|
||||
public R<Integer> add(@Validated @RequestBody StoreProdVO storeProdVO) {
|
||||
public R<Integer> add(@Validated @RequestBody StoreProdVO storeProdVO) throws IOException {
|
||||
return R.ok(storeProdService.insertStoreProduct(BeanUtil.toBean(storeProdVO, StoreProdDTO.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改档口商品
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:product:edit')")
|
||||
// @PreAuthorize("@ss.hasPermi('system:product:edit')")
|
||||
@ApiOperation(value = "修改档口商品", httpMethod = "PUT", response = R.class)
|
||||
@Log(title = "档口商品", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{storeProdId}")
|
||||
public R<Integer> edit(@PathVariable Long storeProdId, @Validated @RequestBody StoreProdVO storeProdVO) {
|
||||
public R<Integer> edit(@PathVariable Long storeProdId, @Validated @RequestBody StoreProdVO storeProdVO) throws IOException {
|
||||
return R.ok(storeProdService.updateStoreProduct(storeProdId, BeanUtil.toBean(storeProdVO, StoreProdDTO.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改档口商品状态
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:product:edit')")
|
||||
// @PreAuthorize("@ss.hasPermi('system:product:edit')")
|
||||
@Log(title = "修改档口商品状态", businessType = BusinessType.UPDATE)
|
||||
@ApiOperation(value = "修改档口商品状态", httpMethod = "PUT", response = R.class)
|
||||
@PutMapping("/prod-status")
|
||||
public R editProdStatus(@Validated @RequestBody StoreProdStatusVO prodStatusVO) {
|
||||
public R editProdStatus(@Validated @RequestBody StoreProdStatusVO prodStatusVO) throws IOException {
|
||||
storeProdService.updateStoreProductStatus(BeanUtil.toBean(prodStatusVO, StoreProdStatusDTO.class));
|
||||
return R.ok();
|
||||
}
|
||||
|
|
@ -118,7 +119,7 @@ public class StoreProductController extends XktBaseController {
|
|||
/**
|
||||
* 获取档口图片空间
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:product:query')")
|
||||
// @PreAuthorize("@ss.hasPermi('system:product:query')")
|
||||
@ApiOperation(value = "获取档口图片空间", httpMethod = "GET", response = R.class)
|
||||
@GetMapping(value = "/pic-space/{storeId}")
|
||||
public R<StoreProdPicSpaceResVO> getStoreProductPicSpace(@PathVariable("storeId") Long storeId) {
|
||||
|
|
@ -129,7 +130,7 @@ public class StoreProductController extends XktBaseController {
|
|||
/**
|
||||
* 导出档口商品列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('system:product:export')")
|
||||
// @PreAuthorize("@ss.hasPermi('system:product:export')")
|
||||
@Log(title = "档口商品", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, StoreProduct storeProduct) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class StoreProdStatusVO {
|
|||
@NotNull(message = "档口商品ID不能为空!")
|
||||
@ApiModelProperty(value = "档口商品ID", required = true)
|
||||
private List<Long> storeProdIdList;
|
||||
@NotBlank(message = "档口商品状态不能为空!")
|
||||
@NotNull(message = "档口商品状态不能为空!")
|
||||
@ApiModelProperty(value = "档口商品状态", required = true)
|
||||
private Integer prodStatus;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,9 +30,15 @@ public class StoreProdVO {
|
|||
@ApiModelProperty(value = "档口ID", required = true)
|
||||
@NotNull(message = "档口ID不能为空!")
|
||||
private Long storeId;
|
||||
@ApiModelProperty(value = "档口名称")
|
||||
@NotBlank(message = "档口名称不能为空!")
|
||||
private String storeName;
|
||||
@ApiModelProperty(value = "商品分类ID", required = true)
|
||||
@NotNull(message = "商品分类ID不能为空!")
|
||||
private Long prodCateId;
|
||||
@ApiModelProperty(value = "商品分类名称")
|
||||
@NotBlank(message = "商品分类名称不能为空!")
|
||||
private String prodCateName;
|
||||
@ApiModelProperty(value = "工厂货号")
|
||||
@Size(min = 0, max = 15, message = "工厂货号不能超过60个字!")
|
||||
private String factoryArtNum;
|
||||
|
|
|
|||
|
|
@ -211,6 +211,8 @@ public class Constants
|
|||
public static final String EXPRESS_REGION_LIST_CACHE_KEY = "EXPRESS_REGION_LIST";
|
||||
public static final String EXPRESS_REGION_TREE_CACHE_KEY = "EXPRESS_REGION_TREE";
|
||||
|
||||
// ES 索引 product_info
|
||||
public static final String ES_IDX_PRODUCT_INFO = "product_info";
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 调度任务信息操作处理
|
||||
*
|
||||
|
|
@ -52,7 +54,7 @@ public class DailySaleController extends BaseController {
|
|||
}
|
||||
|
||||
@PostMapping("/prod-tag")
|
||||
public R dailyProdTag(SysJob sysJob) {
|
||||
public R dailyProdTag(SysJob sysJob) throws IOException {
|
||||
task.dailyProdTag();
|
||||
return R.ok();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
package com.ruoyi.quartz.task;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import co.elastic.clients.elasticsearch.core.BulkResponse;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.constant.HttpStatus;
|
||||
import com.ruoyi.common.core.domain.entity.SysProductCategory;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.framework.es.EsClientWrapper;
|
||||
import com.ruoyi.quartz.domain.*;
|
||||
import com.ruoyi.quartz.dto.DailySaleCusDTO;
|
||||
import com.ruoyi.quartz.dto.DailySaleDTO;
|
||||
|
|
@ -19,11 +22,11 @@ import com.ruoyi.xkt.enums.*;
|
|||
import com.ruoyi.xkt.mapper.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
|
|
@ -56,6 +59,7 @@ public class XktTask {
|
|||
final DailyProdTagMapper dailyProdTagMapper;
|
||||
final StoreProductCategoryAttributeMapper cateAttrMapper;
|
||||
final StoreProductStatisticsMapper prodStatMapper;
|
||||
final EsClientWrapper esClientWrapper;
|
||||
|
||||
/**
|
||||
* 每晚1点同步档口销售数据
|
||||
|
|
@ -211,7 +215,7 @@ public class XktTask {
|
|||
* 给商品打标
|
||||
*/
|
||||
@Transactional
|
||||
public void dailyProdTag() {
|
||||
public void dailyProdTag() throws IOException {
|
||||
// 先删除所有的商品标签,保证数据唯一性
|
||||
List<DailyProdTag> existList = this.dailyProdTagMapper.selectList(new LambdaQueryWrapper<DailyProdTag>()
|
||||
.eq(DailyProdTag::getDelFlag, Constants.UNDELETED));
|
||||
|
|
@ -241,12 +245,15 @@ public class XktTask {
|
|||
return;
|
||||
}
|
||||
this.dailyProdTagMapper.insert(tagList);
|
||||
// 更新商品的标签到ES
|
||||
this.updateESTags(tagList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 每日更新档口商品的各项权重数据
|
||||
*/
|
||||
@Transactional
|
||||
public void dailyProdWeight() {
|
||||
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
|
||||
.eq(StoreProduct::getDelFlag, Constants.UNDELETED));
|
||||
|
|
@ -309,10 +316,10 @@ public class XktTask {
|
|||
/**
|
||||
* 给商品打标 七日上新
|
||||
*
|
||||
* @param yesterday 昨天
|
||||
* @param fourDaysAgo 4天前
|
||||
* @param oneWeekAgo 一周前
|
||||
* @param tagList 标签列表
|
||||
* @param yesterday 昨天
|
||||
* @param fourDaysAgo 4天前
|
||||
* @param oneWeekAgo 一周前
|
||||
* @param tagList 标签列表
|
||||
*/
|
||||
private void tagSevenDayNew(Date yesterday, Date fourDaysAgo, Date oneWeekAgo, List<DailyProdTag> tagList) {
|
||||
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
|
||||
|
|
@ -545,6 +552,31 @@ public class XktTask {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新商品的标签到ES
|
||||
*
|
||||
* @param tagList 标签集合
|
||||
* @throws IOException
|
||||
*/
|
||||
private void updateESTags(List<DailyProdTag> tagList) throws IOException {
|
||||
// 构建一个批量数据集合
|
||||
List<BulkOperation> list = new ArrayList<>();
|
||||
tagList.stream().collect(Collectors.groupingBy(DailyProdTag::getStoreProdId))
|
||||
.forEach((storeProdId, tags) -> {
|
||||
// 构建部分文档更新请求
|
||||
list.add(new BulkOperation.Builder().update(u -> u
|
||||
.action(a -> a.doc(new HashMap<String, Object>() {{
|
||||
put("tags", tags.stream().map(DailyProdTag::getTag).collect(Collectors.toList()));
|
||||
}}))
|
||||
.id(String.valueOf(storeProdId))
|
||||
.index(Constants.ES_IDX_PRODUCT_INFO))
|
||||
.build());
|
||||
});
|
||||
// 调用bulk方法执行批量更新操作
|
||||
BulkResponse bulkResponse = esClientWrapper.getEsClient().bulk(e -> e.index(Constants.ES_IDX_PRODUCT_INFO).operations(list));
|
||||
System.out.println("bulkResponse.items() = " + bulkResponse.items());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.ruoyi.system.mapper;
|
|||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.common.core.domain.entity.SysProductCategory;
|
||||
import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO;
|
||||
|
||||
/**
|
||||
* 商品分类 数据层
|
||||
|
|
@ -10,4 +11,12 @@ import com.ruoyi.common.core.domain.entity.SysProductCategory;
|
|||
*/
|
||||
public interface SysProductCategoryMapper extends BaseMapper<SysProductCategory> {
|
||||
|
||||
/**
|
||||
* 获取当前分类的父类
|
||||
*
|
||||
* @param prodCateId 当前分类
|
||||
* @return ProdCateDTO
|
||||
*/
|
||||
ProdCateDTO getParentCate(Long prodCateId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?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="com.ruoyi.system.mapper.SysProductCategoryMapper">
|
||||
|
||||
<select id="getParentCate" parameterType="Long" resultType="com.ruoyi.system.domain.dto.productCategory.ProdCateDTO">
|
||||
SELECT
|
||||
spc2.id AS prodCateId,
|
||||
spc2.`name` AS `name`
|
||||
FROM
|
||||
sys_product_category spc1
|
||||
LEFT JOIN sys_product_category spc2 ON spc1.parent_id = spc2.id
|
||||
WHERE
|
||||
spc1.del_flag = 0
|
||||
AND spc1.id = #{prodCateId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -3,6 +3,7 @@ package com.ruoyi.xkt.dto.es;
|
|||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ import java.util.List;
|
|||
*/
|
||||
@ApiModel("ES返回商品数据")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ESProductDTO {
|
||||
|
||||
@ApiModelProperty(value = "货号")
|
||||
|
|
@ -40,7 +42,7 @@ public class ESProductDTO {
|
|||
@ApiModelProperty(value = "适合季节")
|
||||
private String season;
|
||||
@ApiModelProperty(value = "商品状态")
|
||||
private String status;
|
||||
private String prodStatus;
|
||||
@ApiModelProperty(value = "档口ID")
|
||||
private String storeId;
|
||||
@ApiModelProperty(value = "档口名称")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
package com.ruoyi.xkt.dto.storeProduct;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author liujiang
|
||||
* @version v1.0
|
||||
* @date 2025/3/27 15:12
|
||||
*/
|
||||
@ApiModel("ES返回商品数据")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class ProductESDTO {
|
||||
|
||||
@ApiModelProperty(value = "档口商品ID")
|
||||
private Long id;
|
||||
@ApiModelProperty(value = "货号")
|
||||
private String prodArtNum;
|
||||
@ApiModelProperty(value = "档口商品分类ID")
|
||||
private String prodCateId;
|
||||
@ApiModelProperty(value = "档口商品分类名称")
|
||||
private String prodCateName;
|
||||
@ApiModelProperty(value = "销量权重")
|
||||
private String saleWeight;
|
||||
@ApiModelProperty(value = "推荐权重")
|
||||
private String recommendWeight;
|
||||
@ApiModelProperty(value = "人气权重")
|
||||
private String popularityWeight;
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private String createTime;
|
||||
@ApiModelProperty(value = "主图")
|
||||
private String mainPic;
|
||||
@ApiModelProperty(value = "上级分类名称")
|
||||
private String parCateName;
|
||||
@ApiModelProperty(value = "上级分类ID")
|
||||
private String parCateId;
|
||||
@ApiModelProperty(value = "单价")
|
||||
private String prodPrice;
|
||||
@ApiModelProperty(value = "适合季节")
|
||||
private String season;
|
||||
@ApiModelProperty(value = "商品状态")
|
||||
private String prodStatus;
|
||||
@ApiModelProperty(value = "档口ID")
|
||||
private String storeId;
|
||||
@ApiModelProperty(value = "档口名称")
|
||||
private String storeName;
|
||||
@ApiModelProperty(value = "风格")
|
||||
private String style;
|
||||
@ApiModelProperty(value = "标签")
|
||||
private List<String> tags;
|
||||
@ApiModelProperty(value = "标题")
|
||||
private String prodTitle;
|
||||
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import io.swagger.annotations.ApiModelProperty;
|
|||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
|
@ -34,8 +35,12 @@ public class StoreProdDTO {
|
|||
private String prodName;
|
||||
@ApiModelProperty(value = "档口ID")
|
||||
private Long storeId;
|
||||
@ApiModelProperty(value = "档口名称")
|
||||
private String storeName;
|
||||
@ApiModelProperty(value = "商品分类ID")
|
||||
private Long prodCateId;
|
||||
@ApiModelProperty(value = "商品分类名称")
|
||||
private String prodCateName;
|
||||
@ApiModelProperty(value = "工厂货号")
|
||||
private String factoryArtNum;
|
||||
@ApiModelProperty(value = "商品货号")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.ruoyi.xkt.mapper;
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.xkt.domain.StoreProduct;
|
||||
import com.ruoyi.xkt.dto.storeHomepage.StoreHomeResDTO;
|
||||
import com.ruoyi.xkt.dto.storeProduct.ProductESDTO;
|
||||
import com.ruoyi.xkt.dto.storeProduct.StoreProdFuzzyResPicDTO;
|
||||
import com.ruoyi.xkt.dto.storeProduct.StoreProdStatusCountDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
|
@ -81,4 +82,12 @@ public interface StoreProductMapper extends BaseMapper<StoreProduct> {
|
|||
* @return StoreProdCountDTO
|
||||
*/
|
||||
StoreProdStatusCountDTO selectStatusCount(Long storeId);
|
||||
|
||||
/**
|
||||
* 档口商品ID列表
|
||||
* @param idList id列表
|
||||
* @return List<ProductESDTO>
|
||||
*/
|
||||
List<ProductESDTO> selectESDTOList(@Param("idList") List<Long> idList);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.ruoyi.common.core.page.Page;
|
|||
import com.ruoyi.xkt.domain.StoreProduct;
|
||||
import com.ruoyi.xkt.dto.storeProduct.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +47,7 @@ public interface IStoreProductService {
|
|||
* @param storeProdDTO 档口商品
|
||||
* @return 结果
|
||||
*/
|
||||
int insertStoreProduct(StoreProdDTO storeProdDTO);
|
||||
int insertStoreProduct(StoreProdDTO storeProdDTO) throws IOException;
|
||||
|
||||
/**
|
||||
* 修改档口商品
|
||||
|
|
@ -54,14 +55,14 @@ public interface IStoreProductService {
|
|||
* @param storeProdDTO 档口商品
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateStoreProduct(Long storeProdId, StoreProdDTO storeProdDTO);
|
||||
public int updateStoreProduct(Long storeProdId, StoreProdDTO storeProdDTO) throws IOException;
|
||||
|
||||
/**
|
||||
* 更新档口商品状态
|
||||
*
|
||||
* @param prodStatusDTO 更新状态入参
|
||||
*/
|
||||
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO);
|
||||
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException;
|
||||
|
||||
/**
|
||||
* 批量删除档口商品
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import co.elastic.clients.elasticsearch._types.query_dsl.*;
|
|||
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
||||
import co.elastic.clients.elasticsearch.core.search.Hit;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.core.page.Page;
|
||||
import com.ruoyi.framework.es.EsClientWrapper;
|
||||
import com.ruoyi.xkt.dto.es.ESProductDTO;
|
||||
|
|
@ -42,7 +43,6 @@ public class IndexSearchServiceImpl implements IIndexSearchService {
|
|||
@Transactional(readOnly = true)
|
||||
public Page<ESProductDTO> search(IndexSearchDTO searchDTO) throws IOException {
|
||||
|
||||
String indexName = "product_info";
|
||||
/*// 查询索引
|
||||
GetIndexResponse res = esClientWrapper.getEsClient().indices().get(request -> request.index(indexName));
|
||||
System.err.println(res);
|
||||
|
|
@ -55,70 +55,8 @@ public class IndexSearchServiceImpl implements IIndexSearchService {
|
|||
System.err.println(response);*/
|
||||
// 分页查询
|
||||
|
||||
// 如果有搜索词,则要分词
|
||||
if (StringUtils.isNotBlank(searchDTO.getSearch())) {
|
||||
}
|
||||
|
||||
|
||||
// 多个query 根据入参是否为空 分别赋值,有multi_match , terms , range
|
||||
|
||||
|
||||
/*SearchResponse<ESProductInfo> list = esClientWrapper.getEsClient().search(s -> s
|
||||
.index(indexName)
|
||||
.query(q -> q
|
||||
.bool(b -> b
|
||||
.must(m -> m
|
||||
.multiMatch(mm -> mm
|
||||
.query(searchDTO.getSearch())
|
||||
.fields("prodTitle", "prodArtNum", "storeName"))
|
||||
)
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("prodCateId")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getProdCateIdList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build()
|
||||
))
|
||||
)
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("parCateId")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getParCateIdList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build())))
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("style.keyword")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getStyleList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build())))
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("season.keyword")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getSeasonList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build())))
|
||||
)
|
||||
)
|
||||
.from(0)
|
||||
.size(10)
|
||||
.sort(sort -> sort.field(f -> f.field("recommendWeight").order(SortOrder.Desc)))
|
||||
,
|
||||
ESProductInfo.class
|
||||
);*/
|
||||
|
||||
|
||||
// 构建 bool 查询
|
||||
BoolQuery.Builder boolQuery = new BoolQuery.Builder();
|
||||
|
||||
// 添加 price 范围查询
|
||||
if (searchDTO.getMinPrice() != null && searchDTO.getMaxPrice() != null) {
|
||||
RangeQuery.Builder builder = new RangeQuery.Builder();
|
||||
|
|
@ -173,7 +111,7 @@ public class IndexSearchServiceImpl implements IIndexSearchService {
|
|||
// 构建最终的查询
|
||||
Query query = new Query.Builder().bool(boolQuery.build()).build();
|
||||
// 执行搜索
|
||||
SearchResponse<ESProductDTO> resList = esClientWrapper.getEsClient().search(s -> s.index(indexName)
|
||||
SearchResponse<ESProductDTO> resList = esClientWrapper.getEsClient().search(s -> s.index(Constants.ES_IDX_PRODUCT_INFO)
|
||||
.query(query).from(searchDTO.getPageNum() - 1).size(searchDTO.getPageSize())
|
||||
.sort(sort -> sort.field(f -> f.field(searchDTO.getSort()).order(SortOrder.Desc))),
|
||||
ESProductDTO.class);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package com.ruoyi.xkt.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import co.elastic.clients.elasticsearch.core.BulkResponse;
|
||||
import co.elastic.clients.elasticsearch.core.CreateResponse;
|
||||
import co.elastic.clients.elasticsearch.core.UpdateResponse;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
|
@ -9,7 +13,11 @@ import com.ruoyi.common.constant.HttpStatus;
|
|||
import com.ruoyi.common.core.page.Page;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.framework.es.EsClientWrapper;
|
||||
import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO;
|
||||
import com.ruoyi.system.mapper.SysProductCategoryMapper;
|
||||
import com.ruoyi.xkt.domain.*;
|
||||
import com.ruoyi.xkt.dto.es.ESProductDTO;
|
||||
import com.ruoyi.xkt.dto.storeColor.StoreColorDTO;
|
||||
import com.ruoyi.xkt.dto.storeProdCateAttr.StoreProdCateAttrDTO;
|
||||
import com.ruoyi.xkt.dto.storeProdColor.StoreProdColorDTO;
|
||||
|
|
@ -22,6 +30,7 @@ import com.ruoyi.xkt.dto.storeProduct.*;
|
|||
import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileDTO;
|
||||
import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileResDTO;
|
||||
import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO;
|
||||
import com.ruoyi.xkt.enums.EProductStatus;
|
||||
import com.ruoyi.xkt.enums.FileType;
|
||||
import com.ruoyi.xkt.enums.ProductSizeStatus;
|
||||
import com.ruoyi.xkt.mapper.*;
|
||||
|
|
@ -33,6 +42,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -59,6 +70,9 @@ public class StoreProductServiceImpl implements IStoreProductService {
|
|||
final StoreProductColorSizeMapper storeProdColorSizeMapper;
|
||||
final StoreProductProcessMapper storeProdProcMapper;
|
||||
final StoreMapper storeMapper;
|
||||
final EsClientWrapper esClientWrapper;
|
||||
final SysProductCategoryMapper prodCateMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 查询档口商品
|
||||
|
|
@ -157,9 +171,10 @@ public class StoreProductServiceImpl implements IStoreProductService {
|
|||
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertStoreProduct(StoreProdDTO storeProdDTO) {
|
||||
public int insertStoreProduct(StoreProdDTO storeProdDTO) throws IOException {
|
||||
// 组装StoreProduct数据
|
||||
StoreProduct storeProd = BeanUtil.toBean(storeProdDTO, StoreProduct.class).setVoucherDate(DateUtils.getNowDate());
|
||||
StoreProduct storeProd = BeanUtil.toBean(storeProdDTO, StoreProduct.class).setVoucherDate(DateUtils.getNowDate())
|
||||
.setRecommendWeight(0L).setSaleWeight(0L).setPopularityWeight(0L);
|
||||
int count = this.storeProdMapper.insert(storeProd);
|
||||
// 处理编辑档口商品颜色
|
||||
this.handleStoreProdColorList(storeProdDTO.getColorList(), storeProd.getId(), storeProd.getStoreId(), Boolean.TRUE);
|
||||
|
|
@ -167,6 +182,8 @@ public class StoreProductServiceImpl implements IStoreProductService {
|
|||
this.handleStoreProdColorSizeList(storeProdDTO.getSizeList(), storeProd.getId(), Boolean.TRUE);
|
||||
// 处理StoreProduct其它属性
|
||||
this.handleStoreProdProperties(storeProd, storeProdDTO);
|
||||
// 向ES索引: product_info 创建文档
|
||||
this.createESDoc(storeProd, storeProdDTO);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +196,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
|
|||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateStoreProduct(final Long storeProdId, StoreProdDTO storeProdDTO) {
|
||||
public int updateStoreProduct(final Long storeProdId, StoreProdDTO storeProdDTO) throws IOException {
|
||||
StoreProduct storeProd = Optional.ofNullable(this.storeProdMapper.selectOne(new LambdaQueryWrapper<StoreProduct>()
|
||||
.eq(StoreProduct::getId, storeProdId).eq(StoreProduct::getDelFlag, Constants.UNDELETED)))
|
||||
.orElseThrow(() -> new ServiceException("档口商品不存在!", HttpStatus.ERROR));
|
||||
|
|
@ -204,9 +221,12 @@ public class StoreProductServiceImpl implements IStoreProductService {
|
|||
this.handleStoreProdColorList(storeProdDTO.getColorList(), storeProdId, storeProd.getStoreId(), Boolean.FALSE);
|
||||
// 处理编辑档口商品颜色尺码
|
||||
this.handleStoreProdColorSizeList(storeProdDTO.getSizeList(), storeProdId, Boolean.FALSE);
|
||||
// 更新索引: product_info 的文档
|
||||
this.updateESDoc(storeProd, storeProdDTO);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理店铺商品颜色尺码列表
|
||||
*
|
||||
|
|
@ -325,19 +345,36 @@ public class StoreProductServiceImpl implements IStoreProductService {
|
|||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) {
|
||||
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException {
|
||||
// 根据商品ID列表查询数据库中的商品信息
|
||||
List<StoreProduct> storeProdList = this.storeProdMapper.selectByIds(prodStatusDTO.getStoreProdIdList());
|
||||
// 检查查询结果是否为空,如果为空,则抛出异常
|
||||
if (CollectionUtils.isEmpty(storeProdList)) {
|
||||
throw new ServiceException("档口商品不存在!", HttpStatus.ERROR);
|
||||
}
|
||||
List<StoreProduct> reSaleList = new ArrayList<>();
|
||||
// 遍历查询到的商品列表,设置新的商品状态
|
||||
storeProdList.forEach(x -> x.setProdStatus(prodStatusDTO.getProdStatus()));
|
||||
storeProdList.forEach(x -> {
|
||||
// 已下架上的商品重新上架
|
||||
if (Objects.equals(x.getProdStatus(), EProductStatus.OFF_SALE.getValue())
|
||||
&& Objects.equals(prodStatusDTO.getProdStatus(), EProductStatus.ON_SALE.getValue())) {
|
||||
reSaleList.add(x);
|
||||
}
|
||||
x.setProdStatus(prodStatusDTO.getProdStatus());
|
||||
});
|
||||
// 保存更新后的商品列表到数据库
|
||||
this.storeProdMapper.updateById(storeProdList);
|
||||
// 筛选商品状态为已下架,则删除ES文档
|
||||
if (Objects.equals(prodStatusDTO.getProdStatus(), EProductStatus.OFF_SALE.getValue())) {
|
||||
this.deleteESDoc(prodStatusDTO.getStoreProdIdList());
|
||||
}
|
||||
// 已下架的商品重新上架
|
||||
if (CollectionUtils.isNotEmpty(reSaleList)) {
|
||||
this.reSaleCreateESDoc(reSaleList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量删除档口商品
|
||||
*
|
||||
|
|
@ -478,4 +515,105 @@ public class StoreProductServiceImpl implements IStoreProductService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向ES索引新增文档
|
||||
*
|
||||
* @param storeProd 档口产品
|
||||
* @param storeProdDTO 档口产品新增入参
|
||||
* @throws IOException
|
||||
*/
|
||||
private void createESDoc(StoreProduct storeProd, StoreProdDTO storeProdDTO) throws IOException {
|
||||
ESProductDTO esProductDTO = this.getESDTO(storeProd, storeProdDTO);
|
||||
// 向索引中添加数据
|
||||
CreateResponse createResponse = esClientWrapper.getEsClient().create(e -> e.index(Constants.ES_IDX_PRODUCT_INFO)
|
||||
.id(storeProd.getId().toString()).document(esProductDTO));
|
||||
System.out.println("createResponse.result() = " + createResponse.result());
|
||||
}
|
||||
|
||||
/**
|
||||
* 向ES索引更新文档
|
||||
*
|
||||
* @param storeProd 档口商品
|
||||
* @param storeProdDTO 档口商品更新入参
|
||||
* @throws IOException
|
||||
*/
|
||||
private void updateESDoc(StoreProduct storeProd, StoreProdDTO storeProdDTO) throws IOException {
|
||||
ESProductDTO esProductDTO = this.getESDTO(storeProd, storeProdDTO);
|
||||
UpdateResponse<ESProductDTO> updateResponse = esClientWrapper.getEsClient().update(u -> u
|
||||
.index(Constants.ES_IDX_PRODUCT_INFO).doc(esProductDTO).id(storeProd.getId().toString()), ESProductDTO.class);
|
||||
System.out.println("deleteResponse.result() = " + updateResponse.result());
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装ES 入参 DTO
|
||||
*
|
||||
* @param storeProd 档口商品
|
||||
* @param storeProdDTO 档口商品更新入参
|
||||
* @return
|
||||
*/
|
||||
private ESProductDTO getESDTO(StoreProduct storeProd, StoreProdDTO storeProdDTO) {
|
||||
// 获取第一张主图
|
||||
String firstMainPic = storeProdDTO.getFileList().stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue()))
|
||||
.min(Comparator.comparing(StoreProdFileDTO::getOrderNum)).map(StoreProdFileDTO::getFileUrl)
|
||||
.orElseThrow(() -> new ServiceException("商品主图不存在!", HttpStatus.ERROR));
|
||||
// 获取上一级分类的分类ID 及 分类名称
|
||||
ProdCateDTO parCate = this.prodCateMapper.getParentCate(storeProdDTO.getProdCateId());
|
||||
// 获取当前商品的最低价格
|
||||
BigDecimal minPrice = storeProdDTO.getPriceList().stream().min(Comparator.comparing(StoreProdColorPriceDTO::getPrice))
|
||||
.map(StoreProdColorPriceDTO::getPrice).orElseThrow(() -> new ServiceException("商品价格不存在!", HttpStatus.ERROR));
|
||||
// 获取使用季节
|
||||
String season = storeProdDTO.getCateAttrList().stream().filter(x -> Objects.equals(x.getDictType(), "suitable_season"))
|
||||
.map(StoreProdCateAttrDTO::getDictValue).findAny().orElse("");
|
||||
// 获取风格
|
||||
String style = storeProdDTO.getCateAttrList().stream().filter(x -> Objects.equals(x.getDictType(), "style"))
|
||||
.map(StoreProdCateAttrDTO::getDictValue).findAny().orElse("");
|
||||
return BeanUtil.toBean(storeProd, ESProductDTO.class)
|
||||
.setProdCateName(storeProdDTO.getProdCateName()).setSaleWeight("0").setRecommendWeight("0").setPopularityWeight("0")
|
||||
.setCreateTime(DateUtils.getTime()).setStoreName(storeProdDTO.getStoreName()).setMainPic(firstMainPic)
|
||||
.setParCateId(parCate.getProdCateId().toString()).setParCateName(parCate.getName()).setProdPrice(minPrice.toString())
|
||||
.setSeason(season).setStyle(style).setTags(Collections.singletonList(style));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除ES索引文档
|
||||
*
|
||||
* @param storeProdIdList 文档ID列表
|
||||
* @throws IOException
|
||||
*/
|
||||
private void deleteESDoc(List<Long> storeProdIdList) throws IOException {
|
||||
List<BulkOperation> list = storeProdIdList.stream().map(x -> new BulkOperation.Builder().delete(
|
||||
d -> d.id(String.valueOf(x)).index(Constants.ES_IDX_PRODUCT_INFO)).build()).collect(Collectors.toList());
|
||||
// 调用bulk方法执行批量插入操作
|
||||
BulkResponse bulkResponse = esClientWrapper.getEsClient().bulk(e -> e.index(Constants.ES_IDX_PRODUCT_INFO).operations(list));
|
||||
System.out.println("bulkResponse.items() = " + bulkResponse.items());
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新创建ES索引下的文档
|
||||
*
|
||||
* @param reSaleList 重新上架商品列表
|
||||
* @throws IOException
|
||||
*/
|
||||
private void reSaleCreateESDoc(List<StoreProduct> reSaleList) throws IOException {
|
||||
if (CollectionUtils.isEmpty(reSaleList)) {
|
||||
return;
|
||||
}
|
||||
List<ProductESDTO> esDTOList = this.storeProdMapper.selectESDTOList(reSaleList.stream()
|
||||
.map(StoreProduct::getId).distinct().collect(Collectors.toList()));
|
||||
Map<Long, ProductESDTO> esDTOMap = esDTOList.stream().collect(Collectors.toMap(ProductESDTO::getId, Function.identity()));
|
||||
// 构建一个批量数据集合
|
||||
List<BulkOperation> list = reSaleList.stream().map(x -> {
|
||||
final String createTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, x.getCreateTime());
|
||||
final ProductESDTO esDTO = Optional.ofNullable(esDTOMap.get(x.getId())).orElseThrow(() -> new ServiceException("档口商品不存在!", HttpStatus.ERROR));
|
||||
ESProductDTO esProductDTO = BeanUtil.toBean(x, ESProductDTO.class).setProdCateName(esDTO.getProdCateName()).setMainPic(esDTO.getMainPic())
|
||||
.setParCateId(esDTO.getParCateId()).setParCateName(esDTO.getParCateName()).setProdPrice(esDTO.getProdPrice()).setStoreName(esDTO.getStoreName())
|
||||
.setSeason(esDTO.getSeason()).setStyle(esDTO.getStyle()).setCreateTime(createTime);
|
||||
return new BulkOperation.Builder().create(d -> d.document(esProductDTO).id(String.valueOf(x.getId()))
|
||||
.index(Constants.ES_IDX_PRODUCT_INFO)).build();
|
||||
}).collect(Collectors.toList());
|
||||
// 调用bulk方法执行批量插入操作
|
||||
BulkResponse bulkResponse = esClientWrapper.getEsClient().bulk(e -> e.index(Constants.ES_IDX_PRODUCT_INFO).operations(list));
|
||||
System.out.println("bulkResponse.items() = " + bulkResponse.items());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,5 +176,37 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
del_flag = 0 AND store_id = #{storeId}
|
||||
</select>
|
||||
|
||||
<select id="selectESDTOList" resultType="com.ruoyi.xkt.dto.storeProduct.ProductESDTO">
|
||||
SELECT DISTINCT
|
||||
sp.id,
|
||||
s.store_name AS storeName,
|
||||
sf.file_url AS mainPic,
|
||||
spca1.dict_value AS season,
|
||||
spca2.dict_value AS style,
|
||||
spcp.min_price AS prodPrice,
|
||||
spc1.`name` AS prodCateName,
|
||||
spc2.id AS parCateId,
|
||||
spc2.`name` AS parCateName
|
||||
FROM
|
||||
store_product sp
|
||||
LEFT JOIN store s ON sp.store_id = s.id
|
||||
LEFT JOIN store_product_file spf ON sp.id = spf.store_prod_id
|
||||
AND spf.file_type = 1
|
||||
AND spf.order_num = 1
|
||||
LEFT JOIN sys_file sf ON spf.file_id = sf.id
|
||||
LEFT JOIN store_product_category_attribute spca1 ON sp.id = spca1.store_prod_id
|
||||
AND spca1.dict_type = 'suitable_season'
|
||||
LEFT JOIN sys_product_category spc1 ON sp.prod_cate_id = spc1.id
|
||||
LEFT JOIN sys_product_category spc2 ON spc1.parent_id = spc2.id
|
||||
LEFT JOIN store_product_category_attribute spca2 ON sp.id = spca2.store_prod_id
|
||||
AND spca2.dict_type = 'style'
|
||||
LEFT JOIN ( SELECT store_prod_id, MIN( price ) AS min_price FROM store_product_color_price GROUP BY store_prod_id ) spcp ON sp.id = spcp.store_prod_id
|
||||
WHERE
|
||||
sp.del_flag = 0 AND sp.id IN
|
||||
<foreach item="id" collection="idList" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
Loading…
Reference in New Issue