master:推广营销查询最近20天上新商品;

pull/1121/head
liujiang 2025-06-07 23:05:16 +08:00
parent 220640c098
commit a30417649c
12 changed files with 249 additions and 65 deletions

View File

@ -45,17 +45,17 @@ public class StoreProductController extends XktBaseController {
}
/**
*
*
*/
@ApiOperation(value = "模糊查询档口商品", httpMethod = "GET", response = R.class)
@GetMapping(value = "/fuzzy/color")
public R<List<StoreProdFuzzyResVO>> fuzzyQueryColorList(@RequestParam(value = "prodArtNum", required = false) String prodArtNum,
@RequestParam("storeId") Long storeId) {
return R.ok(BeanUtil.copyToList(storeProdService.fuzzyQueryList(storeId, prodArtNum), StoreProdFuzzyResVO.class));
public R<List<StoreProdFuzzyColorResVO>> fuzzyQueryColorList(@RequestParam(value = "prodArtNum", required = false) String prodArtNum,
@RequestParam("storeId") Long storeId) {
return R.ok(BeanUtil.copyToList(storeProdService.fuzzyQueryColorList(storeId, prodArtNum), StoreProdFuzzyColorResVO.class));
}
/**
*
*
*/
@ApiOperation(value = "模糊查询档口商品", httpMethod = "GET", response = R.class)
@GetMapping(value = "/fuzzy/pic")
@ -64,6 +64,17 @@ public class StoreProductController extends XktBaseController {
return R.ok(BeanUtil.copyToList(storeProdService.fuzzyQueryResPicList(storeId, prodArtNum), StoreProdFuzzyResPicVO.class));
}
/**
* 广20
*/
@ApiOperation(value = "推广营销新品馆模糊查询最新20天上新商品", httpMethod = "GET", response = R.class)
@GetMapping(value = "/fuzzy/latest20")
public R<List<StoreProdFuzzyLatest20ResVO>> fuzzyQueryLatest20List(@RequestParam(value = "prodArtNum", required = false) String prodArtNum,
@RequestParam("storeId") Long storeId) {
return R.ok(BeanUtil.copyToList(storeProdService.fuzzyQueryLatest20List(storeId, prodArtNum), StoreProdFuzzyLatest20ResVO.class));
}
/**
*
*/
@ -135,9 +146,18 @@ public class StoreProductController extends XktBaseController {
@Log(title = "修改档口商品状态", businessType = BusinessType.UPDATE)
@ApiOperation(value = "修改档口商品状态", httpMethod = "PUT", response = R.class)
@PutMapping("/prod-status")
public R editProdStatus(@Validated @RequestBody StoreProdStatusVO prodStatusVO) throws IOException {
storeProdService.updateStoreProductStatus(BeanUtil.toBean(prodStatusVO, StoreProdStatusDTO.class));
return R.ok();
public R<Integer> editProdStatus(@Validated @RequestBody StoreProdStatusVO prodStatusVO) throws IOException {
return R.ok(storeProdService.updateStoreProductStatus(BeanUtil.toBean(prodStatusVO, StoreProdStatusDTO.class)));
}
/**
*
*/
@Log(title = "删除商品", businessType = BusinessType.DELETE)
@ApiOperation(value = "删除商品", httpMethod = "DELETE", response = R.class)
@DeleteMapping()
public R<Integer> batchDelete(@Validated @RequestBody StoreProdDeleteVO deleteVO) throws IOException {
return R.ok(storeProdService.batchDelete(BeanUtil.toBean(deleteVO, StoreProdDeleteDTO.class)));
}
/**

View File

@ -0,0 +1,26 @@
package com.ruoyi.web.controller.xkt.vo.storeProd;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("档口商品删除")
@Data
public class StoreProdDeleteVO {
@NotNull(message = "档口ID不能为空!")
@ApiModelProperty(value = "档口ID", required = true)
private Long storeId;
@NotNull(message = "档口商品ID不能为空!")
@ApiModelProperty(value = "档口商品ID", required = true)
private List<Long> storeProdIdList;
}

View File

@ -17,7 +17,7 @@ import java.util.List;
@Data
@Builder
@Accessors(chain = true)
public class StoreProdFuzzyResVO {
public class StoreProdFuzzyColorResVO {
@ApiModelProperty(value = "档口商品ID")
private Long storeProdId;
@ -26,10 +26,10 @@ public class StoreProdFuzzyResVO {
@ApiModelProperty(value = "商品货号")
private String prodArtNum;
@ApiModelProperty(value = "商品颜色列表")
private List<StoreProdFuzzyColorResVO> colorList;
private List<SPFCColorVO> colorList;
@Data
public static class StoreProdFuzzyColorResVO {
public static class SPFCColorVO {
@ApiModelProperty(value = "档口颜色ID")
private Long storeColorId;
@ApiModelProperty(value = "颜色名称")

View File

@ -0,0 +1,25 @@
package com.ruoyi.web.controller.xkt.vo.storeProd;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("推广营销查询最近20天上新产品")
@Data
public class StoreProdFuzzyLatest20ResVO {
@ApiModelProperty(value = "档口商品ID")
private Long storeProdId;
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "商品货号")
private String prodArtNum;
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.xkt.dto.storeProduct;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("档口商品删除")
@Data
public class StoreProdDeleteDTO {
@ApiModelProperty(value = "档口ID", required = true)
private Long storeId;
@ApiModelProperty(value = "档口商品ID", required = true)
private List<Long> storeProdIdList;
}

View File

@ -18,7 +18,7 @@ import java.util.List;
@Data
@Builder
@Accessors(chain = true)
public class StoreProdFuzzyResDTO {
public class StoreProdFuzzyColorResDTO {
@ApiModelProperty("档口商品ID")
private Long storeProdId;
@ -27,11 +27,11 @@ public class StoreProdFuzzyResDTO {
@ApiModelProperty(value = "商品货号")
private String prodArtNum;
@ApiModelProperty("商品下颜色列表")
private List<StoreProdFuzzyColorResDTO> colorList;
private List<SPFCColorDTO> colorList;
@Data
@RequiredArgsConstructor
public static class StoreProdFuzzyColorResDTO {
public static class SPFCColorDTO {
@ApiModelProperty("档口颜色ID")
private Long storeColorId;
@ApiModelProperty("颜色名称")

View File

@ -0,0 +1,26 @@
package com.ruoyi.xkt.dto.storeProduct;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("推广营销查询最近20天上新产品")
@Data
@Accessors(chain = true)
public class StoreProdFuzzyLatest20ResDTO {
@ApiModelProperty(value = "档口商品ID")
private Long storeProdId;
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "商品货号")
private String prodArtNum;
}

View File

@ -1,5 +1,7 @@
package com.ruoyi.xkt.enums;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
@ -26,7 +28,7 @@ public enum EProductStatus {
return e;
}
}
return null;
throw new ServiceException("未知商品状态", HttpStatus.ERROR);
}
/**

View File

@ -63,7 +63,7 @@ public interface IStoreProductService {
*
* @param prodStatusDTO
*/
void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException;
Integer updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException;
/**
* ID
@ -72,7 +72,7 @@ public interface IStoreProductService {
* @param prodArtNum
* @return List<StoreProdFuzzyResDTO>
*/
List<StoreProdFuzzyResDTO> fuzzyQueryList(Long storeId, String prodArtNum);
List<StoreProdFuzzyColorResDTO> fuzzyQueryColorList(Long storeId, String prodArtNum);
/**
* ID
@ -141,4 +141,21 @@ public interface IStoreProductService {
* @return StoreProdStatusCateCountResDTO
*/
List<StoreProdStatusCateCountResDTO> getStatusCateNum(StoreProdStatusCateNumDTO dto);
/**
*
*
* @param deleteDTO
* @return Integer
*/
Integer batchDelete(StoreProdDeleteDTO deleteDTO) throws IOException;
/**
* 广20
*
* @param storeId ID
* @param prodArtNum
* @return List<StoreProdFuzzyLatest20ResDTO>
*/
List<StoreProdFuzzyLatest20ResDTO> fuzzyQueryLatest20List(Long storeId, String prodArtNum);
}

View File

@ -100,7 +100,7 @@ public class PictureSearchServiceImpl implements IPictureSearchService {
if (CollectionUtils.isEmpty(results)) {
return BeanUtil.copyToList(picSearchAdverts, StoreProdViewDTO.class);
}
// 档口商品显示的基本属性
// 档口商品显示的基本属性 数据库筛选必须要带prodStatus因为图搜搜出来的可能是下架的商品
List<StoreProdViewDTO> storeProdViewAttrList = this.storeProdMapper.getStoreProdViewAttr(results.stream()
.map(ProductMatchDTO::getStoreProductId).distinct().collect(Collectors.toList()),
java.sql.Date.valueOf(LocalDate.now().minusMonths(2)), java.sql.Date.valueOf(LocalDate.now()));

View File

@ -58,6 +58,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
@ -425,59 +426,74 @@ public class StoreProductServiceImpl implements IStoreProductService {
}
}
/**
*
* ID
*
*
* @param prodStatusDTO ID
* @throws ServiceException
* @param prodStatusDTO
*/
@Override
@Transactional
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException {
public Integer updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException {
// 判断商品状态是否不存在
EProductStatus.of(prodStatusDTO.getProdStatus());
// 根据商品ID列表查询数据库中的商品信息
List<StoreProduct> storeProdList = this.storeProdMapper.selectByIds(prodStatusDTO.getStoreProdIdList());
// 检查查询结果是否为空,如果为空,则抛出异常
List<StoreProduct> storeProdList = Optional.ofNullable(this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
.in(StoreProduct::getId, prodStatusDTO.getStoreProdIdList()).eq(StoreProduct::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("商品不存在!", HttpStatus.ERROR));
storeProdList.forEach(x -> x.setProdStatus(prodStatusDTO.getProdStatus()));
int count = this.storeProdMapper.updateById(storeProdList).size();
// 更新ES中商品状态
this.updateESProdStatus(prodStatusDTO);
return count;
}
/**
*
*
* @param deleteDTO
* @return Integer
*/
@Override
@Transactional
public Integer batchDelete(StoreProdDeleteDTO deleteDTO) throws IOException {
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
.eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, deleteDTO.getStoreId())
.in(StoreProduct::getId, deleteDTO.getStoreProdIdList()));
if (CollectionUtils.isEmpty(storeProdList)) {
throw new ServiceException("档口商品不存在!", HttpStatus.ERROR);
return 0;
}
List<StoreProduct> reSaleList = new ArrayList<>();
// 遍历查询到的商品列表,设置新的商品状态
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())) {
// 删除ES中商品
this.deleteESDoc(prodStatusDTO.getStoreProdIdList());
// 搜图服务同步
prodStatusDTO.getStoreProdIdList().forEach(spId -> sync2ImgSearchServer(spId, ListUtil.empty()));
// 新增消息通知
this.offSaleOrReSaleProd(storeProdList, Boolean.TRUE, prodStatusDTO.getStoreId());
}
// 已下架的商品重新上架
if (CollectionUtils.isNotEmpty(reSaleList)) {
this.reSaleCreateESDoc(reSaleList);
// 搜图服务同步
Map<Long, List<String>> picKeyGroupMap = storeProdFileMapper.selectMainPicByStoreProdIdList(
reSaleList.stream().map(StoreProduct::getId).collect(Collectors.toList()),
FileType.MAIN_PIC.getValue(), null
).stream().collect(Collectors.groupingBy(StoreProdMainPicDTO::getStoreProdId,
Collectors.mapping(StoreProdMainPicDTO::getFileUrl, Collectors.toList())));
prodStatusDTO.getStoreProdIdList()
.forEach(spId -> sync2ImgSearchServer(spId, picKeyGroupMap.get(spId), true));
// 新增消息通知
this.offSaleOrReSaleProd(storeProdList, Boolean.FALSE, prodStatusDTO.getStoreId());
storeProdList.forEach(x -> x.setDelFlag(Constants.DELETED));
int count = this.storeProdMapper.updateById(storeProdList).size();
// 删除ES中商品
this.deleteESDoc(deleteDTO.getStoreProdIdList());
// 搜图服务同步
deleteDTO.getStoreProdIdList().forEach(spId -> sync2ImgSearchServer(spId, ListUtil.empty()));
// 新增消息通知
this.offSaleOrReSaleProd(storeProdList, Boolean.TRUE, deleteDTO.getStoreId());
return count;
}
/**
* 广20
*
* @param storeId ID
* @param prodArtNum
* @return List<StoreProdFuzzyLatest20ResDTO>
*/
@Override
@Transactional(readOnly = true)
public List<StoreProdFuzzyLatest20ResDTO> fuzzyQueryLatest20List(Long storeId, String prodArtNum) {
LocalDateTime daysAgo = LocalDateTime.now().minusDays(20).withHour(0).withMinute(0).withSecond(0);
LambdaQueryWrapper<StoreProduct> queryWrapper = new LambdaQueryWrapper<StoreProduct>()
.eq(StoreProduct::getStoreId, storeId).eq(StoreProduct::getDelFlag, Constants.UNDELETED)
.between(StoreProduct::getCreateTime, daysAgo, LocalDateTime.now());
if (StringUtils.isNotBlank(prodArtNum)) {
queryWrapper.like(StoreProduct::getProdArtNum, prodArtNum);
}
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(queryWrapper);
return storeProdList.stream().map(x -> new StoreProdFuzzyLatest20ResDTO().setStoreId(x.getStoreId())
.setStoreProdId(x.getId()).setProdArtNum(x.getProdArtNum())).collect(Collectors.toList());
}
@ -497,9 +513,10 @@ public class StoreProductServiceImpl implements IStoreProductService {
*/
@Override
@Transactional(readOnly = true)
public List<StoreProdFuzzyResDTO> fuzzyQueryList(Long storeId, String prodArtNum) {
public List<StoreProdFuzzyColorResDTO> fuzzyQueryColorList(Long storeId, String prodArtNum) {
// 初始化查询条件,确保查询的是指定商店且未删除的产品
LambdaQueryWrapper<StoreProduct> queryWrapper = new LambdaQueryWrapper<StoreProduct>()
.in(StoreProduct::getProdStatus, Arrays.asList(EProductStatus.ON_SALE.getValue(), EProductStatus.TAIL_GOODS.getValue()))
.eq(StoreProduct::getStoreId, storeId).eq(StoreProduct::getDelFlag, Constants.UNDELETED);
// 如果产品货号非空,添加模糊查询条件
if (StringUtils.isNotBlank(prodArtNum)) {
@ -517,12 +534,12 @@ public class StoreProductServiceImpl implements IStoreProductService {
List<StoreProductColor> colorList = this.storeProdColorMapper.selectList(new LambdaQueryWrapper<StoreProductColor>()
.in(StoreProductColor::getStoreProdId, storeProdIdList).eq(StoreProductColor::getDelFlag, Constants.UNDELETED));
// 将颜色信息按产品ID分组并转换为所需的颜色DTO列表
Map<Long, List<StoreProdFuzzyResDTO.StoreProdFuzzyColorResDTO>> colorMap = CollectionUtils.isEmpty(colorList) ? new HashMap<>()
Map<Long, List<StoreProdFuzzyColorResDTO.SPFCColorDTO>> colorMap = CollectionUtils.isEmpty(colorList) ? new HashMap<>()
: colorList.stream().collect(Collectors.groupingBy(StoreProductColor::getStoreProdId, Collectors
.collectingAndThen(Collectors.toList(), list -> list.stream().map(y -> BeanUtil.toBean(y, StoreProdFuzzyResDTO.StoreProdFuzzyColorResDTO.class))
.collectingAndThen(Collectors.toList(), list -> list.stream().map(y -> BeanUtil.toBean(y, StoreProdFuzzyColorResDTO.SPFCColorDTO.class))
.collect(Collectors.toList()))));
// 将产品列表转换为所需的产品DTO列表并关联颜色信息
return storeProdList.stream().map(x -> BeanUtil.toBean(x, StoreProdFuzzyResDTO.class).setStoreProdId(x.getId())
return storeProdList.stream().map(x -> BeanUtil.toBean(x, StoreProdFuzzyColorResDTO.class).setStoreProdId(x.getId())
.setColorList(colorMap.getOrDefault(x.getId(), new ArrayList<>()))).collect(Collectors.toList());
}
@ -747,6 +764,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
return countList;
}
/**
* sku
*
@ -1112,5 +1130,27 @@ public class StoreProductServiceImpl implements IStoreProductService {
this.userNoticeMapper.insert(userNoticeList);
}
/**
* @param statusDTO DTO
* @throws IOException
*/
private void updateESProdStatus(StoreProdStatusDTO statusDTO) throws IOException {
// 构建一个批量数据集合
List<BulkOperation> list = new ArrayList<>();
statusDTO.getStoreProdIdList().forEach(storeProdId -> {
// 构建部分文档更新请求
list.add(new BulkOperation.Builder().update(u -> u
.action(a -> a.doc(new HashMap<String, Object>() {{
put("prodStatus", statusDTO.getProdStatus());
}}))
.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());
}
}

View File

@ -16,6 +16,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN sys_file sf ON spf.file_id = sf.id
WHERE
sp.del_flag = 0
AND sp.prod_status IN (2,3)
AND spf.order_num = 1
AND spf.file_type = 1
AND sp.store_id = #{storeId}
@ -97,6 +98,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN sys_file sf ON spf.file_id = sf.id
WHERE
sp.del_flag = 0
AND sp.prod_status IN (2,3)
AND sp.id IN
<foreach item="id" collection="storeProdIdList" open="(" separator="," close=")">
#{id}
@ -132,6 +134,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN sys_product_category spc ON sp.prod_cate_id = spc.id
WHERE
sp.del_flag = 0
AND sp.prod_status IN (2,3)
AND sp.id IN
<foreach item="id" collection="storeProdIdList" open="(" separator="," close=")">
#{id}
@ -164,6 +167,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN daily_prod_tag dpt ON sp.id = dpt.store_prod_id AND dpt.del_flag = 0
WHERE
sp.del_flag = 0
AND sp.prod_status IN (2,3)
AND sp.id IN
<foreach item="id" collection="storeProdIdList" open="(" separator="," close=")">
#{id}