新增超市商品图库批量匹配功能

This commit is contained in:
liyj 2025-06-25 18:17:30 +08:00
parent 4ad20c0f51
commit 0189a7e9cd
22 changed files with 976 additions and 230 deletions

View File

@ -39,42 +39,55 @@ public class ShopProductBase implements Serializable{
private Long product_id;
@ApiModelProperty(value = "产品名称(in=>2,100)")
@TableField(updateStrategy=NOT_EMPTY)
private String product_name;
@ApiModelProperty(value = "商品货号")
@TableField(updateStrategy=NOT_EMPTY)
private String product_number;
@ApiModelProperty(value = "商品卖点:商品广告词")
@TableField(updateStrategy=NOT_EMPTY)
private String product_tips;
@ApiModelProperty(value = "店铺编号")
@TableField(updateStrategy=NOT_EMPTY)
private Integer store_id;
@ApiModelProperty(value = "店铺名称")
@TableField(updateStrategy=NOT_EMPTY)
private String store_name;
@ApiModelProperty(value = "市场价")
@TableField(updateStrategy=NOT_EMPTY)
private BigDecimal product_market_price;
@ApiModelProperty(value = "商品单价")
@TableField(updateStrategy=NOT_EMPTY)
private BigDecimal product_unit_price;
@ApiModelProperty(value = "成本价")
@TableField(updateStrategy=NOT_EMPTY)
private BigDecimal product_cost_price;
@ApiModelProperty(value = "商品主图")
@TableField(updateStrategy=NOT_EMPTY)
private String product_image;
@ApiModelProperty(value = "产品视频 ")
@TableField(updateStrategy=NOT_EMPTY)
private String product_video;
@ApiModelProperty(value = "选择售卖区域:完成售卖区域及运费设置")
@TableField(updateStrategy=NOT_EMPTY)
private Integer transport_type_id;
@ApiModelProperty(value = "如果启用跳转页面")
@TableField(updateStrategy=NOT_EMPTY)
private String product_seo_url;
@ApiModelProperty(value = "专题布局编号")
@TableField(updateStrategy=NOT_EMPTY)
private Integer layout_route_id;
@ApiModelProperty(value = "商品审核(ENUM):3001-审核通过;3002-审核中;3000-审核未通过")
@ -86,48 +99,63 @@ public class ShopProductBase implements Serializable{
private Integer product_state_id;
@ApiModelProperty(value = "库存锁定(ENUM):1001-下单锁定;1002-支付锁定;")
@TableField(updateStrategy=NOT_EMPTY)
private Integer product_inventory_lock;
@ApiModelProperty(value = "上架时间:预设上架时间,可以动态修正状态")
@TableField(updateStrategy=NOT_EMPTY)
private Date product_sale_time;
@ApiModelProperty(value = "计量单位")
@TableField(updateStrategy=NOT_EMPTY)
private Integer unit_id;
@ApiModelProperty(value = "原产国")
@TableField(updateStrategy=NOT_EMPTY)
private String product_country;
@ApiModelProperty(value = "币值")
@TableField(updateStrategy=NOT_EMPTY)
private String product_currency;
@ApiModelProperty(value = "商品添加时间")
@TableField(updateStrategy=NOT_EMPTY)
private Long product_add_time;
@ApiModelProperty(value = "积分单价")
@TableField(updateStrategy=NOT_EMPTY)
private BigDecimal product_unit_points;
@ApiModelProperty(value = "资源2单价")
@TableField(updateStrategy=NOT_EMPTY)
private Integer product_unit_sp;
@ApiModelProperty(value = "排序")
@TableField(updateStrategy=NOT_EMPTY)
private Integer product_order;
@ApiModelProperty(value = "产品来源编号")
@TableField(updateStrategy=NOT_EMPTY)
private Long product_src_id;
@ApiModelProperty(value = "供应状态(BOOL):1-启用分销;0-禁用分销")
@TableField(updateStrategy=NOT_EMPTY)
private Integer product_fx_enable;
@ApiModelProperty(value = "三级分销(BOOL):1-启用分销;0-禁用分销")
@TableField(updateStrategy=NOT_EMPTY)
private Integer product_dist_enable;
@ApiModelProperty(value = "平台佣金百分比")
@TableField(updateStrategy=NOT_EMPTY)
private BigDecimal product_commission_rate;
@ApiModelProperty(value = "商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅;")
@TableField(updateStrategy=NOT_EMPTY)
private Integer product_from;
@ApiModelProperty(value = "来源网址")
@TableField(updateStrategy=NOT_EMPTY)
private String product_from_url;
@ApiModelProperty(value = "商品表-SKU表数据")
@ -136,6 +164,7 @@ public class ShopProductBase implements Serializable{
//在同步数据的时候生鲜需要按平台的规格拆分售卖这些主要记录原始数据总重量一般为kgKG公斤
@ApiModelProperty(value = "总量单位")
@TableField(updateStrategy=NOT_EMPTY)
private String unit_name;
@ApiModelProperty(value = "总重量")

View File

@ -62,5 +62,13 @@ public class ShopProductImage implements Serializable {
@ApiModelProperty(value = "扩展图片")
private String item_image_ext_2;
@ApiModelProperty(value = "商品货号同步数据用")
private String product_number;
@ApiModelProperty(value = "产品名称同步数据用")
private String product_name;
@ApiModelProperty(value = "商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅;同步数据匹配")
private String product_from;
}

View File

@ -0,0 +1,40 @@
package com.suisung.mall.common.modules.sync;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class ImageMappingDto {
@ApiModelProperty(value = "商品图片编号")
private Long productImageId;
@ApiModelProperty(value = "产品编号:product_id-color_id")
private Long productId;
@ApiModelProperty(value = "店铺编号")
private Integer storeId;
@ApiModelProperty(value = "合并图库url")
private String mergedImageUrl;
@ApiModelProperty(value = "主图")
private String thumb;
@ApiModelProperty(value = "图库商品名称")
private String imgProductName;
/**
* 为URL添加域名前缀如果URL不是以http/https开头
*
* @param imageDomain 图片域名
* @param url 图片URL
* @return 添加域名前缀后的URL
*/
public String addDomainPrefix(String imageDomain, String url) {
if (url == null || url.startsWith("http://") || url.startsWith("https://")) {
return url;
}
return imageDomain + (url.startsWith("/") ? url : "/" + url);
}
}

View File

@ -0,0 +1,55 @@
package com.suisung.mall.common.modules.sync;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
@TableName("shop_image_mapping_temp")
@ApiModel("商品图片映射临时表")
public class ShopImageMappingTemp {
@TableId(type = IdType.AUTO)
@ApiModelProperty(value = "临时表ID", example = "1")
private Long id;
@TableField("product_image_id")
@ApiModelProperty(value = "商品图片编号", example = "1001")
private Long productImageId;
@TableField("product_id")
@ApiModelProperty(value = "产品编号(product_id-color_id)", example = "2001-1")
private Long productId;
@TableField("product_name")
@ApiModelProperty(value = "产品名称(同步数据用)", example = "夏季新款T恤")
private String productName;
@TableField("store_id")
@ApiModelProperty(value = "店铺编号", example = "3001")
private Integer storeId;
@TableField("merged_image_url")
@ApiModelProperty(value = "合并后的图片URL", example = "http://example.com/image1.jpg,http://example.com/image2.jpg")
private String mergedImageUrl;
@TableField("name")
@ApiModelProperty(value = "图库商品名", example = "夏季男士短袖T恤")
private String name;
@TableField("thumb")
@ApiModelProperty(value = "主图URL", example = "http://example.com/thumb.jpg")
private String thumb;
@TableField("create_time")
@ApiModelProperty(value = "创建时间", example = "2023-01-01 00:00:00")
private Date createTime;
@TableField("update_time")
@ApiModelProperty(value = "更新时间", example = "2023-01-01 00:00:00")
private Date updateTime;
}

View File

@ -220,7 +220,8 @@ public class AnalyticsOrderServiceImpl implements AnalyticsOrderService {
TimeRange range = TimeUtil.today();
//统计没有取消的订单
List<Integer> orderState = Arrays.asList(StateCode.ORDER_STATE_WAIT_PAY, StateCode.ORDER_STATE_WAIT_PAID, StateCode.ORDER_STATE_WAIT_REVIEW, StateCode.ORDER_STATE_WAIT_FINANCE_REVIEW, StateCode.ORDER_STATE_PICKING, StateCode.ORDER_STATE_WAIT_SHIPPING, StateCode.ORDER_STATE_SHIPPED, StateCode.ORDER_STATE_RECEIVED, StateCode.ORDER_STATE_FINISH, StateCode.ORDER_STATE_SELF_PICKUP);
List<Integer> orderState = Arrays.asList(StateCode.ORDER_STATE_WAIT_PAY, StateCode.ORDER_STATE_WAIT_PAID, StateCode.ORDER_STATE_WAIT_REVIEW, StateCode.ORDER_STATE_WAIT_FINANCE_REVIEW, StateCode.ORDER_STATE_PICKING, StateCode.ORDER_STATE_WAIT_SHIPPING, StateCode.ORDER_STATE_SHIPPED, StateCode.ORDER_STATE_RECEIVED, StateCode.ORDER_STATE_FINISH, StateCode.ORDER_STATE_SELF_PICKUP,
StateCode.ORDER_STATE_CANCEL);
List<Integer> paidState = Arrays.asList(StateCode.ORDER_PAID_STATE_PART, StateCode.ORDER_PAID_STATE_YES);
OrderNumVo todayOrderNum = analyticsOrderDao.getOrderNum(range.getStart(), range.getEnd(), orderState, null, null, null, siteId, storeId);

View File

@ -2,8 +2,13 @@ package com.suisung.mall.shop.product.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.suisung.mall.common.modules.product.ShopProductImage;
import com.suisung.mall.common.modules.sync.ImageMappingDto;
import io.lettuce.core.dynamic.annotation.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* <p>
* 产品图片表按照颜色规格 Mapper 接口
@ -16,4 +21,18 @@ import org.springframework.stereotype.Repository;
@Repository
public interface ShopProductImageMapper extends BaseMapper<ShopProductImage> {
Integer mappingByBarCodeCount(@Param("storeId") Integer storeId);
Integer mappingByProductNameCount(@Param("storeId") Integer storeId);
Integer mappingByProductShortNameCount(@Param("storeId") Integer storeId);
/**
* 1条形码匹配
* 2标准名称匹配
* 3产品名称模糊匹配
* @param type
* @return
*/
List<ImageMappingDto> mappingProductImage(@Param("type") String type,@Param("storeId") Integer storeId,@Param("offset") Integer offset,@Param("limit") Integer limit);
}

View File

@ -286,7 +286,7 @@ public interface ShopProductBaseService extends IBaseService<ShopProductBase> {
Pair<Boolean, String> saveProductBatch(List<ShopProductBase> shopProductBaseList, List<ShopProductIndex> shopProductIndexList,
List<ShopProductData> shopProductDataList, List<ShopProductDetail> shopProductDetailList,
List<ShopProductInfo> shopProductInfoList, List<List<ShopProductItem>> shopProductItemList,
List<List<ShopProductImage>> shopProductImageList,
List<ShopProductImage> shopProductImageList,
List<ShopProductValidPeriod> shopProductValidPeriodList,
List<ShopProductAssistIndex> shopProductAssistIndexList);

View File

@ -5271,7 +5271,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
public Pair<Boolean, String> saveProductBatch(List<ShopProductBase> shopProductBaseList, List<ShopProductIndex> shopProductIndexList,
List<ShopProductData> shopProductDataList, List<ShopProductDetail> shopProductDetailList,
List<ShopProductInfo> shopProductInfoList, List<List<ShopProductItem>> shopProductItemList,
List<List<ShopProductImage>> shopProductImageList, List<ShopProductValidPeriod> shopProductValidPeriodList,
List<ShopProductImage> shopProductImageList, List<ShopProductValidPeriod> shopProductValidPeriodList,
List<ShopProductAssistIndex> shopProductAssistIndexList) {
// 1. 参数校验
@ -5301,8 +5301,8 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
List<List<ShopProductItem>> newShopProductItemList=new ArrayList<>();
List<List<ShopProductItem>> updateShopProductItemList=new ArrayList<>();
List<List<ShopProductImage>> newShopProductImageList=new ArrayList<>();
List<List<ShopProductImage>> updateShopProductImageList=new ArrayList<>();
List<ShopProductImage> newShopProductImageList=new ArrayList<>();
List<ShopProductImage> updateShopProductImageList=new ArrayList<>();
List<ShopProductValidPeriod> newShopProductValidPeriodList=new ArrayList<>();
List<ShopProductValidPeriod> updateShopProductValidPeriodList=new ArrayList<>();
@ -5429,7 +5429,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
List<ShopProductDetail> newShopProductDetailList, List<ShopProductDetail> updateShopProductDetailList,
List<ShopProductInfo> newShopProductInfoList, List<ShopProductInfo> updateShopProductInfoList,
List<List<ShopProductItem>> newShopProductItemList,List<List<ShopProductItem>> udpateShopProductItemList,
List<List<ShopProductImage>> newShopProductImageList, List<List<ShopProductImage>> udpteShopProductImageList,
List<ShopProductImage> newShopProductImageList, List<ShopProductImage> udpteShopProductImageList,
List<ShopProductValidPeriod> newShopProductValidPeriodList, List<ShopProductValidPeriod> updateShopProductValidPeriodList,
List<ShopProductAssistIndex> newShopProductAssistIndexList, List<ShopProductAssistIndex> udpateShopProductAssistIndexList
) {
@ -5472,16 +5472,6 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
newShopProductDataList.get(i).setProduct_id(productId);
newShopProductDetailList.get(i).setProduct_id(productId);
newShopProductInfoList.get(i).setProduct_id(productId);
// newShopProductInfoList.get(i).setProductName(newProducts.get(i).getProduct_name());
//计算规格
// ShopProductSpecItem shopProductSpecItem=processShopProductSpecItem(base);
// if(null!=shopProductSpecItem){
// if(shopProductSpecItem.isUpdate()){
// updateShopProductSpecItems.add(shopProductSpecItem);
// }else {
// addShopProductSpecItems.add(shopProductSpecItem);
// }
// }
// 处理商品项
List<ShopProductItem> items = newShopProductItemList.get(i);
processProductItems(items, productId, addItemSeqs);
@ -5489,7 +5479,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
// 处理图片
if(CollUtil.isNotEmpty(newShopProductImageList)){
processProductImages(newShopProductImageList.get(i), productId,base.getStore_id());
processProductImages(newShopProductImageList.get(i), productId,base.getStore_id(),newProducts.get(i).getProduct_number(),newProducts.get(i).getProduct_name());//设置默认属性1
}
// 处理辅助属性
@ -5531,26 +5521,15 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
updateShopProductDataList.get(i).setProduct_id(productId);
updateShopProductDetailList.get(i).setProduct_id(productId);
updateShopProductInfoList.get(i).setProduct_id(productId);
//updateShopProductInfoList.get(i).setProductName(updateProducts.get(i).getProduct_name());
//计算规格
// ShopProductSpecItem shopProductSpecItem=processShopProductSpecItem(base);
// if(null!=shopProductSpecItem){
// if(shopProductSpecItem.isUpdate()){
// updateShopProductSpecItems.add(shopProductSpecItem);
// }else {
// addShopProductSpecItems.add(shopProductSpecItem);
// }
// }
// 处理商品项
List<ShopProductItem> items = udpateShopProductItemList.get(i);
processProductItems(items, productId, updateItemSeqs);//
updateShopProductItems.addAll(items);
//allItemIds.addAll(itemIds);
// productToItemsMap.put(productId, itemIds);
// 处理图片
if(CollUtil.isNotEmpty(udpteShopProductImageList)){
processProductImages(udpteShopProductImageList.get(i), productId,base.getStore_id());
processProductImages(udpteShopProductImageList.get(i), productId,base.getStore_id(),updateProducts.get(i).getProduct_number(),updateProducts.get(i).getProduct_name());
}
// 处理辅助属性
@ -5584,7 +5563,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
batchProcessOtherTables(newShopProductIndexList,updateShopProductIndexList,newShopProductDataList,updateShopProductDataList,
newShopProductDetailList,updateShopProductDetailList,newShopProductInfoList,updateShopProductInfoList,
newShopProductValidPeriodList,updateShopProductValidPeriodList,addShopProductItems,updateShopProductItems,
addAnalyticsList,udpateAnalyticsList,addItemSeqs,updateItemSeqs);
addAnalyticsList,udpateAnalyticsList,addItemSeqs,updateItemSeqs,newShopProductImageList,udpteShopProductImageList);
logger.info("处理成功,新增{}条,更新{}条", newProducts.size(), updateProducts.size());
//计算规格
@ -5612,7 +5591,8 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
List<ShopProductValidPeriod> newShopProductValidPeriodList,List<ShopProductValidPeriod> updateShopProductValidPeriodList,
List<ShopProductItem> newshopProductItemList,List<ShopProductItem> updateshopProductItemList,
List<ShopProductAnalytics> newShopProductAnalyticList,List<ShopProductAnalytics> updateShopProductAnalyticList,
List<ShopProductItemSeq> newShopProductItemSeqList,List<ShopProductItemSeq> updateShopProductItemSeqList) {
List<ShopProductItemSeq> newShopProductItemSeqList,List<ShopProductItemSeq> updateShopProductItemSeqList,
List<ShopProductImage> addShopProductImageList,List<ShopProductImage> updateShopProductImageList) {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
@ -5660,6 +5640,21 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
logger.info("更新updateShopProductDataList-{}条数据耗时:{}",updateShopProductDataList.size(),duration/1000000000);
// }
}
if(CollectionUtil.isNotEmpty(addShopProductImageList)){
long startTime=System.nanoTime();
shopProductImageService.saveBatch(addShopProductImageList,addShopProductImageList.size());
long endTime = System.nanoTime();
long duration = (endTime - startTime);
logger.info("新增addShopProductImageList-{}条数据耗时:{}",addShopProductImageList.size(),duration/1000000000);
}
// if(CollectionUtil.isNotEmpty(updateShopProductImageList)){
// long startTime=System.nanoTime();
// // shopProductImageService.batchUpdateByCondition(updateShopProductImageList,"product_id");
// // updateBatchById();
// long endTime = System.nanoTime();
// long duration = (endTime - startTime);
// logger.info("更新updateShopProductImageList-{}条数据耗时:{}",updateShopProductImageList.size(),duration/1000000000);
// }
}catch (RuntimeException e){
logger.info("批量报错附表失败{}",e.getMessage());
}
@ -6038,79 +6033,22 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
/**
* 处理商品图片批量操作
* @param productImages 商品图片列表
* @param productImage 商品图片列表
* @param productId 商品ID
*/
private void processProductImages(List<ShopProductImage> productImages, Long productId, Integer storeId) {
if (CollUtil.isEmpty(productImages)) {
private void processProductImages(ShopProductImage productImage, Long productId, Integer storeId,String productNumber,String productName) {
if (ObjectUtil.isEmpty(productImage)) {
return;
}
productImage.setProduct_id(productId);
productImage.setStore_id(storeId);
// 1. 查询现有图片
List<ShopProductImage> existingImages = shopProductImageService.getShopProductImageByStoreId(storeId);
Map<Long, ShopProductImage> existingImageMap = existingImages.stream()
.collect(Collectors.toMap(ShopProductImage::getProduct_image_id, Function.identity()));
// 2. 分离需要新增更新和删除的图片
List<ShopProductImage> toAdd = new ArrayList<>();
List<ShopProductImage> toUpdate = new ArrayList<>();
List<Long> toDelete = new ArrayList<>();
List<String> delBaiduImages = new ArrayList<>();
List<String> addBaiduImages = new ArrayList<>();
for (ShopProductImage newImage : productImages) {
newImage.setProduct_id(productId);
// 设置默认值
newImage.setItem_image_ext_1("");
newImage.setItem_image_ext_2("");
// 判断是新增还是更新
if (newImage.getProduct_image_id() == null) {
toAdd.add(newImage);
if (StrUtil.isNotBlank(newImage.getItem_image_default())) {
addBaiduImages.add(newImage.getItem_image_default());
}
} else {
ShopProductImage oldImage = existingImageMap.get(newImage.getProduct_image_id());
if (oldImage != null) {
// 检查图片是否有变化
if (!StrUtil.equals(oldImage.getItem_image_default(), newImage.getItem_image_default())) {
if (StrUtil.isNotBlank(oldImage.getItem_image_default())) {
delBaiduImages.add(oldImage.getItem_image_default());
}
if (StrUtil.isNotBlank(newImage.getItem_image_default())) {
addBaiduImages.add(newImage.getItem_image_default());
}
}
toUpdate.add(newImage);
}
}
}
// 找出需要删除的图片存在但不在新列表中
existingImages.forEach(oldImage -> {
boolean stillExists = productImages.stream()
.anyMatch(img -> Objects.equals(img.getProduct_image_id(), oldImage.getProduct_image_id()));
if (!stillExists) {
toDelete.add(oldImage.getProduct_image_id());
if (StrUtil.isNotBlank(oldImage.getItem_image_default())) {
delBaiduImages.add(oldImage.getItem_image_default());
}
}
});
// 3. 执行批量操作
if (CollUtil.isNotEmpty(toAdd)) {
shopProductImageService.saveBatch(toAdd,toAdd.size());
}
if (CollUtil.isNotEmpty(toUpdate)) {
shopProductImageService.updateBatchById(toUpdate);
}
if (CollUtil.isNotEmpty(toDelete)) {
shopProductImageService.removeByIds(toDelete);
}
productImage.setColor_id(0L);
productImage.setItem_image_default("1");//设置默认属性1,方便查询匹配图库
productImage.setProduct_number(productNumber);
productImage.setProduct_name(productName);
}
/**
* 处理商品辅助属性批量操作
* @param assistIndices 辅助属性列表

View File

@ -6,10 +6,14 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.api.IErrorCode;
import com.suisung.mall.common.domain.UserDto;
import com.suisung.mall.common.modules.sync.ProductMapping;
import com.suisung.mall.common.pojo.res.ThirdApiRes;
import com.suisung.mall.common.service.impl.BaseControllerImpl;
import com.suisung.mall.common.utils.ContextUtil;
import com.suisung.mall.shop.sync.exelModel.ImportResult;
import com.suisung.mall.shop.sync.service.ProductMappingService;
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
@ -18,6 +22,7 @@ import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
@ -39,6 +44,9 @@ public class ProductMappingController extends BaseControllerImpl {
@Value("${file.upload-dir}")
private String uploadDir;
@Resource
private SyncThirdDataService syncThirdDataService;
/**
* 分页列表查询
* @param pageNum
@ -217,4 +225,18 @@ public class ProductMappingController extends BaseControllerImpl {
}
}
@ApiOperation(value = "商品图库匹配", notes = "商品图库匹配")
@RequestMapping(value = "/syncShopImages", method = RequestMethod.POST)
public ThirdApiRes syncShopImages(@RequestParam(required = false) String storeId) {
UserDto userDto=ContextUtil.getCurrentUser();
assert userDto != null;
if(userDto.isStore()){//商店自己同步
String shopStoreId=userDto.getStore_id();
syncThirdDataService.syncShopImages(Integer.valueOf(shopStoreId));
}else {//平台同步
syncThirdDataService.syncShopImages(Integer.valueOf(storeId));
}
return new ThirdApiRes().success("服务器已执行商品图库匹配数据操作");
}
}

View File

@ -10,15 +10,11 @@ package com.suisung.mall.shop.sync.controller;
import cn.hutool.json.JSONArray;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.modules.sync.StoreDbConfig;
import com.suisung.mall.common.pojo.req.SyncThirdMemberReq;
import com.suisung.mall.common.pojo.res.ThirdApiRes;
import com.suisung.mall.shop.sync.service.SyncAppService;
import com.suisung.mall.shop.sync.service.SyncThirdDataService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -26,7 +22,6 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Api(tags = "第三方数据同步")
@RestController
@ -185,4 +180,5 @@ public class SyncThirdDataController {
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
* Vestibulum commodo. Ut rhoncus gravida arcu.
*/
package com.suisung.mall.shop.sync.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.suisung.mall.common.modules.sync.ShopImageMappingTemp;
import io.lettuce.core.dynamic.annotation.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ShopImageMappingTempMapper extends BaseMapper<ShopImageMappingTemp> {
/**
* 由于模糊匹配数据慢需要把数据放到临时表
* @param storeId
*/
void mergeShopImageMappingTemp(@Param("storeId") Integer storeId);
/**
* 删除临时表数据
* @param storeId
*/
void deleteShopImageMappingTemp(@Param("storeId") Integer storeId);
}

View File

@ -0,0 +1,7 @@
package com.suisung.mall.shop.sync.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.suisung.mall.common.modules.sync.ShopImageMappingTemp;
public interface ShopImageMappingTempService extends IService<ShopImageMappingTemp> {
}

View File

@ -0,0 +1,5 @@
package com.suisung.mall.shop.sync.service;
public interface SyncShopImageService {
void syncMapingShopImages(Integer storeId);
}

View File

@ -156,4 +156,9 @@ public interface SyncThirdDataService {
* @return
*/
void syncActiveShops(String appKey, String sign, JSONArray activeJsonArray);
/**
* 同步匹配商品图库数据
*/
void syncShopImages(Integer storeId);
}

View File

@ -16,7 +16,6 @@ import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.api.StateCode;
@ -165,8 +164,8 @@ public class ProductMappingServiceImpl extends BaseServiceImpl<ProductMappingMap
for (int i = 0; i < shopProductBaseList.size(); i++){
ShopProductSpecItem shopProductSpecItem=processShopProductSpecItem(shopProductBaseList.get(i),shopProductItems.get(i).getCategory_id(),shopProductSpecItemMap,ShopBaseProductSpecMap,productMappingMap,null);
if(shopProductSpecItem!=null){
shopProductBaseList.get(i).setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL);
shopProductItems.get(i).setItem_enable(StateCode.PRODUCT_STATE_NORMAL);
shopProductBaseList.get(i).setProduct_state_id(StateCode.PRODUCT_STATE_OFF_THE_SHELF);
shopProductItems.get(i).setItem_enable(StateCode.PRODUCT_STATE_OFF_THE_SHELF);
shopProductItems.get(i).setItem_is_default(1);
if(shopProductSpecItem.isUpdate()){
shopProductBaseList.get(i).setProduct_unit_price(shopProductSpecItem.getItemPrice());

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
* Vestibulum commodo. Ut rhoncus gravida arcu.
*/
package com.suisung.mall.shop.sync.service.impl;
import com.suisung.mall.common.modules.sync.ShopImageMappingTemp;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.sync.mapper.ShopImageMappingTempMapper;
import com.suisung.mall.shop.sync.service.ShopImageMappingTempService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class ShopImageMappingTempServiceImpl extends BaseServiceImpl<ShopImageMappingTempMapper, ShopImageMappingTemp> implements ShopImageMappingTempService {
}

View File

@ -32,6 +32,7 @@ import com.suisung.mall.common.modules.sixun.SxSyncGoods;
import com.suisung.mall.common.modules.sixun.SxSyncVip;
import com.suisung.mall.common.modules.store.ShopStoreActivityBase;
import com.suisung.mall.common.modules.store.ShopStoreBase;
import com.suisung.mall.common.pojo.dto.LibraryProductDTO;
import com.suisung.mall.common.pojo.req.SyncThirdMemberReq;
import com.suisung.mall.common.utils.DateTimeUtils;
import com.suisung.mall.common.utils.I18nUtil;
@ -41,6 +42,8 @@ import com.suisung.mall.shop.base.service.ShopBaseProductBrandService;
import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService;
import com.suisung.mall.shop.base.service.ShopBaseProductSpecService;
import com.suisung.mall.shop.base.service.ShopBaseProductTypeService;
import com.suisung.mall.shop.library.service.LibraryProductImageService;
import com.suisung.mall.shop.library.service.LibraryProductService;
import com.suisung.mall.shop.number.service.ShopNumberSeqService;
import com.suisung.mall.shop.number.service.impl.ShopNumberSeqServiceImpl;
import com.suisung.mall.shop.product.service.ShopProductBaseService;
@ -95,6 +98,9 @@ public abstract class SyncBaseThirdSxAbstract{
@Autowired
private ShopStoreActivityBaseService shopStoreActivityBaseService;
@Autowired
private LibraryProductService libraryProductService;
/**
* 对商品分类进行保存
* @param list
@ -114,6 +120,7 @@ public abstract class SyncBaseThirdSxAbstract{
JSONObject o = (JSONObject) categoryListJSON.get(i);
ShopBaseProductType productType=new ShopBaseProductType();
productType.setType_is_draft(1);//发布
productType.setStore_id(Integer.valueOf(storeId));
if (o != null) {
// 重要分类类型处理强调共性
Integer typeId = 1001;
@ -127,6 +134,7 @@ public abstract class SyncBaseThirdSxAbstract{
ShopBaseProductType newProductType = new ShopBaseProductType();
newProductType.setType_name(o.getStr("product_type"));
newProductType.setType_buildin(0);
newProductType.setStore_id(Integer.valueOf(storeId));
if (productTypeService.save(newProductType)) {
typeId = newProductType.getType_id();
}
@ -152,6 +160,10 @@ public abstract class SyncBaseThirdSxAbstract{
firstCate.setStore_id(storeId);
firstCate.setType_id(typeId);
firstCate.setData_source(2);
List<LibraryProductDTO> libraryProductDTOS=libraryProductService.matchLibraryProducts(null,o.getStr("first_category_name"),new ArrayList<>());
if(CollectionUtil.isNotEmpty(libraryProductDTOS)){
firstCate.setCategory_image(libraryProductDTOS.get(0).getThumb());
}
if (productCategoryService.saveOrUpdate(firstCate)) {
// 当前子分类的父类id
firstParentId = firstCate.getId();
@ -175,6 +187,11 @@ public abstract class SyncBaseThirdSxAbstract{
secondCate.setStore_id(storeId);
secondCate.setType_id(typeId);
secondCate.setData_source(2);
List<LibraryProductDTO> libraryProductDTOS=libraryProductService.matchLibraryProducts(null,o.getStr("second_category_name"),new ArrayList<>());
if(CollectionUtil.isNotEmpty(libraryProductDTOS)){
secondCate.setCategory_image(libraryProductDTOS.get(0).getThumb());
}
if (productCategoryService.saveOrUpdate(secondCate)) {
// 当前子分类的第二级父类id
list.get(i).setCategory_parent_id(secondCate.getId());
@ -197,6 +214,10 @@ public abstract class SyncBaseThirdSxAbstract{
}
}
List<LibraryProductDTO> libraryProductDTOS=libraryProductService.matchLibraryProducts(null,list.get(i).getCategory_name(),new ArrayList<>());
if(CollectionUtil.isNotEmpty(libraryProductDTOS)){
list.get(i).setCategory_image(libraryProductDTOS.get(0).getThumb());
}
if (productCategoryService.saveOrUpdate(list.get(i))) {
count++;
@ -541,6 +562,7 @@ public abstract class SyncBaseThirdSxAbstract{
List<ShopProductDetail> shopProductDetailList=new ArrayList<>(); ;
List<ShopProductInfo> shopProductInfoList=new ArrayList<>(); ;
List<List<ShopProductItem>> shopProductItemLists=new ArrayList<>();
List<ShopProductImage> shopProductImageList=new ArrayList<>();
ShopStoreBase store_row = shopStoreBaseService.get(storeId);
if (store_row == null) {
throw new ApiException(I18nUtil._("无法获取店铺信息!"));
@ -588,7 +610,7 @@ public abstract class SyncBaseThirdSxAbstract{
shopProductBase.setUnit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
}else {
shopProductBase.setShop_weight(jsonObj.getBigDecimal("stock"));
shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL);
shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_OFF_THE_SHELF);//默认是下架
shopProductBase.setUnit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
}
// ShopProductIndex
@ -653,6 +675,7 @@ public abstract class SyncBaseThirdSxAbstract{
ShopProductItem shopProductItem = new ShopProductItem();
shopProductItem.setStore_id(storeIdInt);
shopProductItem.setCategory_id(categoryId);
shopProductItem.setItem_src_id(jsonObj.getLong("product_number"));
//零售价
shopProductItem.setItem_unit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
shopProductItem.setItem_advice_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price")));
@ -672,6 +695,12 @@ public abstract class SyncBaseThirdSxAbstract{
shopProductItem.setItem_is_default(1);
shopProductItem.setItem_enable(shopProductBase.getProduct_state_id());
//shopProductImage
ShopProductImage shopProductImage = new ShopProductImage();
shopProductImage.setStore_id(storeIdInt);
shopProductImage.setProduct_name(jsonObj.getStr("product_name"));
shopProductImage.setProduct_from("1005");
//添加数据到list
synchronized(shopProductBaseList){
shopProductItemList.add(shopProductItem);
@ -681,12 +710,13 @@ public abstract class SyncBaseThirdSxAbstract{
shopProductDetailList.add(shopProductDetail);
shopProductInfoList.add(shopProductInfo);
shopProductItemLists.add(shopProductItemList);
shopProductImageList.add(shopProductImage);
}
resultCount.addAndGet(1);
});
// 保存数据
shopProductBaseService.saveProductBatch(shopProductBaseList,shopProductIndexList,shopProductDataList,shopProductDetailList,shopProductInfoList,shopProductItemLists,
new ArrayList<List<ShopProductImage>>(),
shopProductImageList,
new ArrayList<ShopProductValidPeriod>(),
new ArrayList<ShopProductAssistIndex>());

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
* Vestibulum commodo. Ut rhoncus gravida arcu.
*/
package com.suisung.mall.shop.sync.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.suisung.mall.common.api.StateCode;
import com.suisung.mall.common.modules.product.ShopProductBase;
import com.suisung.mall.common.modules.product.ShopProductImage;
import com.suisung.mall.common.modules.product.ShopProductItem;
import com.suisung.mall.common.modules.sync.ImageMappingDto;
import com.suisung.mall.common.utils.StringUtils;
import com.suisung.mall.shop.product.mapper.ShopProductImageMapper;
import com.suisung.mall.shop.product.service.ShopProductBaseService;
import com.suisung.mall.shop.product.service.ShopProductImageService;
import com.suisung.mall.shop.product.service.ShopProductItemService;
import com.suisung.mall.shop.sixun.utils.CommonUtil;
import com.suisung.mall.shop.sync.mapper.ShopImageMappingTempMapper;
import com.suisung.mall.shop.sync.service.SyncShopImageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
@Service
@Slf4j
public class SyncShopImageServiceImpl implements SyncShopImageService {
@Autowired
private ShopProductImageMapper shopProductImageMapper;
@Autowired
private ShopImageMappingTempMapper shopImageMappingTempMapper;
@Autowired
private ShopProductImageService shopProductImageService;
@Autowired
private ShopProductItemService shopProductItemService;
@Autowired
private ShopProductBaseService shopProductBaseService;
@Value("${project.static_domain}")
private String staticDomain;
private final static Integer BATCH_SIZE=500;
private final static String MAPPING_BARCODE="1";//条形码匹配
private final static String MAPPING_PRODUCTSHORTNAME="2";//标准名称匹配
private final static String MAPPING_PRODUCTNAME="3";//产品名称模糊匹配
@Override
public void syncMapingShopImages(Integer storeId) {
mappingProductImages(MAPPING_BARCODE,storeId);
mappingProductImages(MAPPING_PRODUCTSHORTNAME,storeId);
mappingProductImages(MAPPING_PRODUCTNAME,storeId);
}
/**
* 通过类型匹配 使用游标方式
* 1条形码匹配
* 2标准名称匹配
* 3产品名称模糊匹配
*/
public void mappingProductImages(String type,Integer storeId){
Integer total=null;
String typename="";
switch (type){
case MAPPING_BARCODE:
typename="条形码匹配";
total= shopProductImageMapper.mappingByBarCodeCount(storeId);
break;
case MAPPING_PRODUCTSHORTNAME:
typename="标准名称匹配";
total= shopProductImageMapper.mappingByProductShortNameCount(storeId);
break;
case MAPPING_PRODUCTNAME:
typename="产品名称模糊匹配";
//先把数据查到临时表再查询
shopImageMappingTempMapper.deleteShopImageMappingTemp(storeId);//匹配结束删除临时表数据
shopImageMappingTempMapper.mergeShopImageMappingTemp(storeId);
total= shopProductImageMapper.mappingByProductNameCount(storeId);
break;
}
if(total!=null&&total<1){
log.info("{}无数据",typename);
return;
}
ExecutorService executor = Executors.newFixedThreadPool(6);
List<Future<?>> futures = new ArrayList<>();
Integer pages= CommonUtil.getPagesCount(total,BATCH_SIZE);
AtomicInteger success = new AtomicInteger();
AtomicInteger fails = new AtomicInteger();
for (int i = 1; i <= pages; i++) {
List<ImageMappingDto> imageMappingDtos = shopProductImageMapper.mappingProductImage(type,storeId,(i-1)*BATCH_SIZE,BATCH_SIZE);
final int finalI = i;
futures.add(executor.submit(() -> {
try {
syncBatchShopImage(imageMappingDtos);
success.getAndIncrement();
return "成功" + finalI;
} catch (Exception e) {
fails.getAndIncrement();
return "失败"+finalI;
}
}));
}
// 等待所有任务完成
for (Future<?> future : futures) {
try {
log.info("任务结果: " + future.get());
} catch (Exception e) {
log.error("任务执行异常: " + e.getMessage());
}
}
executor.shutdown();
log.info("成功:{}条,失败:{}条",success,fails);
}
/**
* 把匹配的数据更新到商品的图库表
* @param imageMappingDtos
*/
private void syncBatchShopImage(List<ImageMappingDto> imageMappingDtos){
if(CollectionUtil.isEmpty(imageMappingDtos)){
log.info("没有匹配到图库");
return;
}
List<ShopProductBase> shopProductBaseList=new ArrayList<>();
List<ShopProductItem> shopProductItemList=new ArrayList<>();
List<ShopProductImage> shopProductImageList=new ArrayList<>();
for (ImageMappingDto imageMappingDto:imageMappingDtos){
String mergedImageUrl=imageMappingDto.getMergedImageUrl();
if(StringUtils.isEmpty(mergedImageUrl)){
continue;
}
ShopProductImage shopProductImage=new ShopProductImage();
ShopProductBase shopProductBase=new ShopProductBase();
ShopProductItem shopProductItem=new ShopProductItem();
if(mergedImageUrl.contains(",")){
String [] imageUrls= mergedImageUrl.split(",");
for (String imageUrl:imageUrls){
shopProductImage.setItem_image_other(imageMappingDto.addDomainPrefix(staticDomain,imageUrl));
}
}else {
shopProductImage.setItem_image_other(imageMappingDto.addDomainPrefix(staticDomain,mergedImageUrl));
}
shopProductImage.setProduct_id(imageMappingDto.getProductId());
shopProductImage.setProduct_image_id(imageMappingDto.getProductImageId());
shopProductImage.setItem_image_default(imageMappingDto.addDomainPrefix(staticDomain,imageMappingDto.getThumb()));
shopProductImageList.add(shopProductImage);
shopProductBase.setProduct_id(imageMappingDto.getProductId());
shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL);
shopProductBaseList.add(shopProductBase);
shopProductItem.setItem_enable(StateCode.PRODUCT_STATE_NORMAL);
shopProductItemList.add(shopProductItem);
}
if(CollectionUtil.isNotEmpty(shopProductImageList)){
shopProductImageService.updateBatchById(shopProductImageList);
}
if(CollectionUtil.isNotEmpty(shopProductBaseList)){
shopProductBaseService.updateBatchById(shopProductBaseList);
}
if(CollectionUtil.isNotEmpty(shopProductItemList)){
shopProductItemService.updateBatchById(shopProductItemList);
}
}
}

View File

@ -153,6 +153,9 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
@Autowired
private ShopStoreActivityBaseService shopStoreActivityBaseService;
@Autowired
private SyncShopImageService syncShopImageService;
/**
* 批量保存商品的分类
*
@ -609,6 +612,12 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
logger.error("同步时间失败" + e.getMessage());
}
syncShopImages(Integer.valueOf(storeId));//同时商品图库数据
}
@Override
public void syncShopImages(Integer storeId){
syncShopImageService.syncMapingShopImages(storeId);
}
@Override
@ -771,7 +780,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
for (Map.Entry<String, Integer> entry : stockDeltaMap.entrySet()) {
String productKey = entry.getKey();
Integer delta = entry.getValue();
if (StrUtil.isBlank(productKey) || productKey.equals("0") || delta == null || delta.equals(0)) {
if (StrUtil.isBlank(productKey) || delta == null) {
continue;
}
@ -847,41 +856,41 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
@Override
public ThirdApiRes fileUploadToOss(String appKey, String sign, String syncType, Date refreshDate, List<String> folders) {
if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign)) {
public ThirdApiRes fileUploadToOss(String appKey, String sign, String syncType,Date refreshDate, List<String> folders) {
if (StrUtil.isBlank(appKey) || StrUtil.isBlank(sign) ) {
return new ThirdApiRes().fail(1003, I18nUtil._("缺少必要参数!"));
}
// 验签appid必要参数判断
SyncApp syncApp = syncAppService.getOne(new LambdaQueryWrapper<SyncApp>()
.select(SyncApp::getApp_key, SyncApp::getApp_secret, SyncApp::getStore_id)
.select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id)
.eq(SyncApp::getApp_key, appKey)
.eq(SyncApp::getApp_secret, sign));
.eq(SyncApp::getApp_secret,sign));
if (syncApp == null) {
return new ThirdApiRes().fail(1001, I18nUtil._("签名有误!"));
}
String storeId = syncApp.getStore_id();
if (null == syncApp.getStore_id() || syncApp.getStore_id().isEmpty()) {
if(null==syncApp.getStore_id()|| syncApp.getStore_id().isEmpty()){
logger.info("商店id为空");
return new ThirdApiRes().fail(250, "商店id为空");
return new ThirdApiRes().fail(250,"商店id为空");
}
if (folders == null || folders.isEmpty()) {
if(folders==null||folders.isEmpty()){
logger.info("没有商品数据");
return new ThirdApiRes().fail(250, "没有商品数据");
return new ThirdApiRes().fail(250,"没有商品数据");
}
String newfolder = new FileUtils().getSyncTypeFlag(syncType, clientPath) + storeId + FileUtils.pathSeparator + folders.get(0) + FileUtils.pathSeparator;
String newfolder=new FileUtils().getSyncTypeFlag(syncType,clientPath)+storeId+FileUtils.pathSeparator+folders.get(0)+FileUtils.pathSeparator;
upLoadZipToOss(newfolder);//上传文件到cos
//更新当前的获取时间用户客户端获取
try {
QueryWrapper<StoreDbConfig> storeDbConfigQueryWrapper = new QueryWrapper<>();
storeDbConfigQueryWrapper.eq("store_id", storeId);
StoreDbConfig storeDbConfig = storeDbConfigService.getOne(storeDbConfigQueryWrapper);
if (ObjectUtil.isNotEmpty(storeDbConfig)) {
StoreDbConfig storeDbConfig=storeDbConfigService.getOne(storeDbConfigQueryWrapper);
if(ObjectUtil.isNotEmpty(storeDbConfig)){
storeDbConfig.setRefreshTime(refreshDate);
storeDbConfigService.saveOrUpdate(storeDbConfig);
}
} catch (RuntimeException e) {
logger.error("同步时间失败" + e.getMessage());
}catch (RuntimeException e){
logger.error("同步时间失败"+e.getMessage());
}
return new ThirdApiRes().success("上传成功");
}
@ -895,9 +904,9 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
}
// 验签appid必要参数判断
SyncApp syncAppO = syncAppService.getOne(new LambdaQueryWrapper<SyncApp>()
.select(SyncApp::getApp_key, SyncApp::getApp_secret, SyncApp::getStore_id)
.select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id)
.eq(SyncApp::getApp_key, appKey)
.eq(SyncApp::getApp_secret, sign));
.eq(SyncApp::getApp_secret,sign));
if (syncAppO == null) {
logger.error("签名有误!");
return;
@ -909,21 +918,20 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
/**
* 批量新增或更新活动数据
*
* @param jsonArray
*/
private void batchSaveShopStoreActivityBase(JSONArray jsonArray, Integer storeId) {
List<ShopStoreActivityBase> addshopStoreActivityBaseList = new ArrayList<>();
List<ShopStoreActivityBase> updateShopStoreActivityBaseList = new ArrayList<>();
Map<String, String> stringIntegerMap = checkExistingActive(jsonArray, storeId);
jsonArray.stream().parallel().forEach(object -> {
final JSONObject jsonObj = (JSONObject) object;
String activityName = jsonObj.getStr("activityName");
Integer activityTypeId = jsonObj.getInt("activityTypeId");
if (null == activityTypeId) {
private void batchSaveShopStoreActivityBase(JSONArray jsonArray,Integer storeId) {
List<ShopStoreActivityBase> addshopStoreActivityBaseList=new ArrayList<>();
List<ShopStoreActivityBase> updateShopStoreActivityBaseList=new ArrayList<>();
Map<String, String> stringIntegerMap= checkExistingActive(jsonArray,storeId);
jsonArray.stream().parallel().forEach(object->{
final JSONObject jsonObj= (JSONObject) object;
String activityName=jsonObj.getStr("activityName");
Integer activityTypeId=jsonObj.getInt("activityTypeId");
if(null==activityTypeId){
return;
}
ShopStoreActivityBase shopStoreActivityBase = new ShopStoreActivityBase();
ShopStoreActivityBase shopStoreActivityBase=new ShopStoreActivityBase();
if (activityTypeId == 1) {
activityTypeId = StateCode.ACTIVITY_TYPE_LIMITED_DISCOUNT; //限时秒杀
}
@ -931,17 +939,17 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
activityTypeId = StateCode.ACTIVITY_TYPE_ONE_PIECE_DISCOUNT; //折扣
}
if (activityTypeId == 3) {
JSONArray activeMaxDesList = jsonObj.getJSONArray("activeMaxDesList");
JSONArray activeMaxDesList=jsonObj.getJSONArray("activeMaxDesList");
activityTypeId = StateCode.ACTIVITY_TYPE_REDUCTION; //满减
String rules = ActiveShopJsonUtils.getRules(activeMaxDesList);
String rules= ActiveShopJsonUtils.getRules(activeMaxDesList);
shopStoreActivityBase.setActivity_rule(rules);
}
Date activityStarttime = jsonObj.getDate("activityStarttime");
Date activityEndtime = jsonObj.getDate("activityEndtime");
Integer activityState = jsonObj.getInt("activityState");
Date activityReleasetime = jsonObj.getDate("activityReleasetime");
BigDecimal discount = jsonObj.getBigDecimal("discount");
String key = activityName + "_" + activityStarttime.getTime() + "_" + activityState;
Date activityStarttime=jsonObj.getDate("activityStarttime");
Date activityEndtime=jsonObj.getDate("activityEndtime");
Integer activityState=jsonObj.getInt("activityState");
Date activityReleasetime= jsonObj.getDate("activityReleasetime");
BigDecimal discount=jsonObj.getBigDecimal("discount");
String key=activityName+"_"+activityStarttime.getTime()+"_"+activityState;
shopStoreActivityBase.setActivity_state(activityState);
shopStoreActivityBase.setActivity_name(activityName);
shopStoreActivityBase.setActivity_type(1);//免费参与
@ -953,19 +961,19 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
shopStoreActivityBase.setActivity_endtime(activityEndtime);
shopStoreActivityBase.setActivity_state(activityState);
shopStoreActivityBase.setSubsite_id(0);
if (stringIntegerMap.containsKey(key)) {//更新
String keyVal = MapUtil.getStr(stringIntegerMap, key);
shopStoreActivityBase.setActivity_id(MapUtil.getInt(stringIntegerMap, keyVal.split("_")[0]));
if(stringIntegerMap.containsKey(key)){//更新
String keyVal= MapUtil.getStr(stringIntegerMap,key);
shopStoreActivityBase.setActivity_id(MapUtil.getInt(stringIntegerMap,keyVal.split("_")[0]));
updateShopStoreActivityBaseList.add(shopStoreActivityBase);
} else {
}else {
addshopStoreActivityBaseList.add(shopStoreActivityBase);
}
});
if (CollectionUtil.isNotEmpty(addshopStoreActivityBaseList)) {
shopStoreActivityBaseService.saveBatch(addshopStoreActivityBaseList, addshopStoreActivityBaseList.size());
if(CollectionUtil.isNotEmpty(addshopStoreActivityBaseList)){
shopStoreActivityBaseService.saveBatch(addshopStoreActivityBaseList,addshopStoreActivityBaseList.size());
}
if (CollectionUtil.isNotEmpty(updateShopStoreActivityBaseList)) {
if(CollectionUtil.isNotEmpty(updateShopStoreActivityBaseList)){
shopStoreActivityBaseService.updateBatchById(updateShopStoreActivityBaseList);
}
@ -976,7 +984,6 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
* 将商品添加到活动
* 1找出匹配的活动
* 2新增商品到活动列表
*
* @param appKey
* @param sign
* @param activeJsonArray
@ -990,9 +997,9 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
}
// 验签appid必要参数判断
SyncApp syncAppO = syncAppService.getOne(new LambdaQueryWrapper<SyncApp>()
.select(SyncApp::getApp_key, SyncApp::getApp_secret, SyncApp::getStore_id)
.select(SyncApp::getApp_key, SyncApp::getApp_secret,SyncApp::getStore_id)
.eq(SyncApp::getApp_key, appKey)
.eq(SyncApp::getApp_secret, sign));
.eq(SyncApp::getApp_secret,sign));
if (syncAppO == null) {
logger.error("签名有误!");
return;
@ -1004,84 +1011,83 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
/**
* 批量新增或更新活动商品数据
*
* @param jsonArray
*/
private void batchAddActiveShopBase(JSONArray jsonArray, Integer storeId) {
List<ShopStoreActivityBase> updateShopStoreActivityBaseList = new ArrayList<>();
Map<String, String> stringIntegerMap = checkExistingActive(jsonArray, storeId);
Map shopProduckKeyMap = shopProductBaseService.getProductBasicIdByStore(storeId);//获取货架号对应的商品id
Map shopItemKeyMap = shopProductItemService.getProductItemIdByStore(storeId);//获取商品id对应的item的id
Map<String, String> rulesChe = new HashMap();//存储rule格式activeId:rules,如果不存在则从数据库取存在则从缓存取数据
jsonArray.forEach(object -> {
final JSONObject jsonObj = (JSONObject) object;
String activityName = jsonObj.getStr("activityName");
Integer activityTypeId = jsonObj.getInt("activityTypeId");
if (null == activityTypeId) {
private void batchAddActiveShopBase(JSONArray jsonArray,Integer storeId) {
List<ShopStoreActivityBase> updateShopStoreActivityBaseList=new ArrayList<>();
Map<String, String> stringIntegerMap= checkExistingActive(jsonArray,storeId);
Map shopProduckKeyMap=shopProductBaseService.getProductBasicIdByStore(storeId);//获取货架号对应的商品id
Map shopItemKeyMap=shopProductItemService.getProductItemIdByStore(storeId);//获取商品id对应的item的id
Map<String,String> rulesChe=new HashMap();//存储rule格式activeId:rules,如果不存在则从数据库取存在则从缓存取数据
jsonArray.forEach(object->{
final JSONObject jsonObj= (JSONObject) object;
String activityName=jsonObj.getStr("activityName");
Integer activityTypeId=jsonObj.getInt("activityTypeId");
if(null==activityTypeId){
return;
}
String ruleType = "";
List<org.json.JSONObject> newItems = new ArrayList<>();
ShopStoreActivityBase shopStoreActivityBase = new ShopStoreActivityBase();
Integer productId = null;
String itemNo = jsonObj.getStr("itemNo");
BigDecimal discount = jsonObj.getBigDecimal("discount");
if (shopProduckKeyMap.containsKey(itemNo)) {
productId = (Integer) shopProduckKeyMap.get(itemNo);
String ruleType="";
List<org.json.JSONObject> newItems=new ArrayList<>();
ShopStoreActivityBase shopStoreActivityBase=new ShopStoreActivityBase();
Integer productId=null;
String itemNo=jsonObj.getStr("itemNo");
BigDecimal discount=jsonObj.getBigDecimal("discount");
if(shopProduckKeyMap.containsKey(itemNo)){
productId= (Integer) shopProduckKeyMap.get(itemNo);
}
if (null == productId) {
if(null==productId){
return;
}
Date activityStarttime = jsonObj.getDate("activityStarttime");
Integer activityState = jsonObj.getInt("activityState");
Date activityStarttime=jsonObj.getDate("activityStarttime");
Integer activityState=jsonObj.getInt("activityState");
String key = activityName + "_" + activityStarttime.getTime() + "_" + activityState;
String key=activityName+"_"+activityStarttime.getTime()+"_"+activityState;
if (stringIntegerMap.containsKey(key)) {//更新
String keyVal = MapUtil.getStr(stringIntegerMap, key);
String activityId = keyVal.split("_")[0];
String rules = "";
if (null != rulesChe.get(activityId)) {
rules = rulesChe.get(activityId);
} else {
rules = keyVal.split("_")[1];
if(stringIntegerMap.containsKey(key)){//更新
String keyVal=MapUtil.getStr(stringIntegerMap,key);
String activityId=keyVal.split("_")[0];
String rules="";
if(null!=rulesChe.get(activityId)){
rules=rulesChe.get(activityId);
}else {
rules=keyVal.split("_")[1];
}
String itemIds = (String) shopItemKeyMap.get(productId);
if (null != itemIds) {
itemIds = (String) shopItemKeyMap.get(String.valueOf(productId));
String itemIds= (String) shopItemKeyMap.get(productId);
if(null!=itemIds){
itemIds= (String) shopItemKeyMap.get(String.valueOf(productId));
}
assert itemIds != null;
if (activityTypeId == 1) {//限时秒杀
ruleType = ActiveShopJsonUtils.SECKILL;
BigDecimal oldPrice = jsonObj.getBigDecimal("oldPrice");
BigDecimal specPrice = jsonObj.getBigDecimal("specPrice");
if (oldPrice.compareTo(BigDecimal.ZERO) > 0 && specPrice.compareTo(BigDecimal.ZERO) > 0) {
BigDecimal newDiscout = specPrice.divide(oldPrice, 4, RoundingMode.HALF_UP);
newItems.addAll(getFulReduItemList(itemIds, ruleType, newDiscout));//获取满减规则的itemid
ruleType=ActiveShopJsonUtils.SECKILL;
BigDecimal oldPrice=jsonObj.getBigDecimal("oldPrice");
BigDecimal specPrice=jsonObj.getBigDecimal("specPrice");
if(oldPrice.compareTo(BigDecimal.ZERO)>0&&specPrice.compareTo(BigDecimal.ZERO)>0){
BigDecimal newDiscout=specPrice.divide(oldPrice,4, RoundingMode.HALF_UP);
newItems.addAll(getFulReduItemList(itemIds,ruleType,newDiscout));//获取满减规则的itemid
}
}
if (activityTypeId == 2) {//折扣
if (discount.compareTo(BigDecimal.ZERO) <= 0) {
if(discount.compareTo(BigDecimal.ZERO)<=0){
logger.error("商品折扣要大于0");
return;
}
ruleType = ActiveShopJsonUtils.DISCOUNT;
newItems.addAll(getFulReduItemList(itemIds, ruleType, discount));//获取满减规则的itemid
ruleType=ActiveShopJsonUtils.DISCOUNT;
newItems.addAll(getFulReduItemList(itemIds,ruleType,discount));//获取满减规则的itemid
}
if (activityTypeId == 3) {//满减
ruleType = ActiveShopJsonUtils.FULLREDUCE;
newItems.addAll(getFulReduItemList(itemIds, ruleType, null));//获取满减规则的itemid
ruleType=ActiveShopJsonUtils.FULLREDUCE;
newItems.addAll(getFulReduItemList(itemIds,ruleType,null));//获取满减规则的itemid
}
shopStoreActivityBase.setActivity_id(MapUtil.getInt(stringIntegerMap, activityId));
String newRules = ActiveShopJsonUtils.buildPromotionRule(ruleType, rules, newItems);
rulesChe.put(activityId, newRules);
shopStoreActivityBase.setActivity_id(MapUtil.getInt(stringIntegerMap,activityId));
String newRules= ActiveShopJsonUtils.buildPromotionRule(ruleType,rules,newItems);
rulesChe.put(activityId,newRules);
shopStoreActivityBase.setActivity_rule(rules);
updateShopStoreActivityBaseList.add(shopStoreActivityBase);
}
});
if (CollectionUtil.isNotEmpty(updateShopStoreActivityBaseList)) {
if(CollectionUtil.isNotEmpty(updateShopStoreActivityBaseList)){
shopStoreActivityBaseService.updateBatchById(updateShopStoreActivityBaseList);
}
@ -1091,59 +1097,58 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
* 一对多如product_id:1002,item_number:120_121;数据格式为item_id,item_id item_unit_price,item_unit_price
* 最终组合item_id,item_id_item_unit_price,item_unit_price
* 满减的切割规则的itemid
*
* @param itemPrice
* @return
*/
private List<org.json.JSONObject> getFulReduItemList(String itemPrice, String activeType, BigDecimal discount) {
List<org.json.JSONObject> newItems = new ArrayList<>();
String[] itemPriceArray = itemPrice.split("_");
String itemIds = itemPriceArray[0];
String unitPrices = itemPriceArray[1];
switch (activeType) {
private List<org.json.JSONObject> getFulReduItemList(String itemPrice,String activeType,BigDecimal discount){
List<org.json.JSONObject> newItems=new ArrayList<>();
String [] itemPriceArray=itemPrice.split("_");
String itemIds=itemPriceArray[0];
String unitPrices=itemPriceArray[1];
switch (activeType){
case ActiveShopJsonUtils.DISCOUNT:
if (itemIds.contains(",")) {
String[] itemIdsArray = itemIds.split(",");
if(itemIds.contains(",")){
String [] itemIdsArray=itemIds.split(",");
for (String itemId : itemIdsArray) {
org.json.JSONObject jsonObject = new org.json.JSONObject();
jsonObject.put("item_id", itemId);
jsonObject.put("rate", BigDecimalFormatter.formatWithoutTrailingZeros(discount.multiply(new BigDecimal(100))));
newItems.add(jsonObject);
}
} else {
org.json.JSONObject jsonObject = new org.json.JSONObject();
jsonObject.put("item_id", itemIds);
}else {
org.json.JSONObject jsonObject=new org.json.JSONObject();
jsonObject.put("item_id",itemIds);
jsonObject.put("rate", BigDecimalFormatter.formatWithoutTrailingZeros(discount.multiply(new BigDecimal(100))));
newItems.add(jsonObject);
}
break;
case ActiveShopJsonUtils.FULLREDUCE:
if (itemIds.contains(",")) {
String[] itemIdsArray = itemIds.split(",");
for (String itemId : itemIdsArray) {
org.json.JSONObject jsonObject = new org.json.JSONObject();
jsonObject.put("item_id", itemId);
if(itemIds.contains(",")){
String [] itemIdsArray=itemIds.split(",");
for(String itemId:itemIdsArray){
org.json.JSONObject jsonObject=new org.json.JSONObject();
jsonObject.put("item_id",itemId);
newItems.add(jsonObject);
}
} else {
org.json.JSONObject jsonObject = new org.json.JSONObject();
jsonObject.put("item_id", itemIds);
}else {
org.json.JSONObject jsonObject=new org.json.JSONObject();
jsonObject.put("item_id",itemIds);
newItems.add(jsonObject);
}
break;
case ActiveShopJsonUtils.SECKILL:
if (itemIds.contains(",")) {
String[] unitPricesArray = unitPrices.split(",");
String[] itemIdsArray = itemIds.split(",");
for (int i = 0; i < itemIdsArray.length; i++) {
if(itemIds.contains(",")){
String [] unitPricesArray=unitPrices.split(",");
String [] itemIdsArray=itemIds.split(",");
for (int i=0;i<itemIdsArray.length;i++) {
org.json.JSONObject jsonObject = new org.json.JSONObject();
jsonObject.put("item_id", itemIdsArray[i]);
jsonObject.put("price", BigDecimalFormatter.formatWithoutTrailingZeros(discount.multiply(new BigDecimal(unitPricesArray[i]))));
newItems.add(jsonObject);
}
} else {
org.json.JSONObject jsonObject = new org.json.JSONObject();
jsonObject.put("item_id", itemIds);
}else {
org.json.JSONObject jsonObject=new org.json.JSONObject();
jsonObject.put("item_id",itemIds);
jsonObject.put("price", BigDecimalFormatter.formatWithoutTrailingZeros(discount.multiply(new BigDecimal(unitPrices))));
newItems.add(jsonObject);
}

View File

@ -0,0 +1,66 @@
<?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.suisung.mall.shop.sync.mapper.ShopImageMappingTempMapper">
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, product_image_id, product_id, product_name, store_id, merged_image_url, thumb,name
</sql>
<insert id="mergeShopImageMappingTemp">
INSERT into shop_image_mapping_temp(product_image_id,product_id,product_name,store_id,merged_image_url,thumb,name)
SELECT
temp.product_image_id,
temp.product_id,
temp.product_name,
temp.store_id,
temp. merged_image_url,
temp.thumb,
temp.name
from
(
SELECT
ROW_NUMBER() over(partition by t.product_name
order by
t.id) rn,
t.*
from
(
SELECT
spi.product_image_id,
spi.product_id,
spi.product_name,
spi.store_id,
lpi. merged_image_url,
lp.thumb,
lp.id,
lp.name
FROM
-- (select * from shop_product_image limit 7500,500) spi
shop_product_image spi
INNER JOIN library_product lp ON
spi.product_name like CONCAT(lp.name,"%")
-- MATCH(spi.product_name) AGAINST(CONCAT(lp.name, '*') IN BOOLEAN MODE)
-- AND spi.product_name LIKE CONCAT(lp.name, '%') -- 保持精确匹配
LEFT JOIN (
SELECT
product_id,
GROUP_CONCAT(image_url SEPARATOR ',') AS merged_image_url
FROM
library_product_image
WHERE
is_main = '0'
GROUP BY
product_id ) lpi ON
lp.id = lpi.product_id
WHERE
spi.product_from = '1005'
AND spi.item_image_default = '1' )t )temp
where
temp.rn = 1 and temp.store_id=#{storeId}
</insert>
<delete id="deleteShopImageMappingTemp">
delete from shop_image_mapping_temp where store_id=#{storeId}
</delete>
</mapper>

View File

@ -8,4 +8,249 @@
item_image_diy, item_video, item_image_ext_1, item_image_ext_2
</sql>
<resultMap id="imageMappingDtoResultMap" type="com.suisung.mall.common.modules.sync.ImageMappingDto">
<id property="productImageId" column="product_image_id" />
<result property="productId" column="product_id" />
<result property="storeId" column="store_id" />
<result property="mergedImageUrl" column="merged_image_url"/>
<result property="thumb" column="thumb"/>
<result property="imgProductName" column="name"/>
</resultMap>
<select id="mappingProductImage" resultMap="imageMappingDtoResultMap">
<if test="type!=null and type=='1'.toString()">
<include refid="mappingByBarCode"></include>
</if>
<if test="type!=null and type=='2'.toString()">
<include refid="mappingByProductShortName"></include>
</if>
<if test="type!=null and type=='3'.toString()">
<include refid="mappingByProductName"></include>
</if>
</select>
<select id="mappingByBarCodeCount" resultType="java.lang.Integer">
select count(1)
from (
SELECT
temp.product_image_id,
temp.product_id,
temp.store_id,
temp. merged_image_url,
temp.thumb,
temp.name
from
(
SELECT
ROW_NUMBER() over(partition by t.product_name order by t.id) rn,t.*
from
(
SELECT
spi.product_image_id,
spi.product_id,
spi.product_name,
spi.store_id,
lpi. merged_image_url,
lp.thumb,
lp.id,
lp.name
FROM
shop_product_image spi
INNER JOIN
library_product lp ON
spi.product_number = lp.barcode
LEFT JOIN
(
SELECT
product_id,
GROUP_CONCAT(image_url SEPARATOR ',') AS merged_image_url
FROM
library_product_image
WHERE
is_main = '0'
GROUP BY
product_id
) lpi ON
lp.id = lpi.product_id
WHERE
spi.product_from = '1005'
AND spi.item_image_default = '1'
<![CDATA[ AND lp.barcode <> '' ]]>)t
)temp
where
temp.rn = 1 and temp.store_id=#{storeId}
)tt
</select>
<sql id="mappingByBarCode">
SELECT
temp.product_image_id,
temp.product_id,
temp.store_id,
temp. merged_image_url,
temp.thumb,
temp.name
from
(
SELECT
ROW_NUMBER() over(partition by t.product_name order by t.id) rn,t.*
from
(
SELECT
spi.product_image_id,
spi.product_id,
spi.product_name,
spi.store_id,
lpi. merged_image_url,
lp.thumb,
lp.id,
lp.name
FROM
shop_product_image spi
INNER JOIN
library_product lp ON
spi.product_number = lp.barcode
LEFT JOIN
(
SELECT
product_id,
GROUP_CONCAT(image_url SEPARATOR ',') AS merged_image_url
FROM
library_product_image
WHERE
is_main = '0'
GROUP BY
product_id
) lpi ON
lp.id = lpi.product_id
WHERE
spi.product_from = '1005'
AND spi.item_image_default = '1'
<![CDATA[ AND lp.barcode <> '' ]]>)t
)temp
where
temp.rn = 1 and temp.store_id=#{storeId} limit #{offset},#{limit}
</sql>
<select id="mappingByProductShortNameCount" resultType="java.lang.Integer">
select count(1)
from (
SELECT
temp.product_image_id,
temp.product_id,
temp.store_id,
temp. merged_image_url,
temp.thumb,
temp.name
from
(
SELECT
ROW_NUMBER() over(partition by t.product_name order by t.id) rn,t.*
from
(
SELECT
spi.product_image_id,
spi.product_id,
spi.product_name,
spi.store_id,
lpi. merged_image_url,
lp.thumb,
lp.id,
lp.name
FROM
shop_product_image spi
INNER JOIN
library_product lp ON
spi.product_short_name = lp.product_short_name
LEFT JOIN
(
SELECT
product_id,
GROUP_CONCAT(image_url SEPARATOR ',') AS merged_image_url
FROM
library_product_image
WHERE
is_main = '0'
GROUP BY
product_id
) lpi ON
lp.id = lpi.product_id
WHERE
spi.product_from = '1005'
AND spi.item_image_default = '1'
<![CDATA[ AND lp.product_short_name <> '' ]]>
)t
)temp
where
temp.rn = 1 and temp.store_id=#{storeId}
)tt
</select>
<sql id="mappingByProductShortName">
SELECT
temp.product_image_id,
temp.product_id,
temp.store_id,
temp. merged_image_url,
temp.thumb,
temp.name
from
(
SELECT
ROW_NUMBER() over(partition by t.product_name order by t.id) rn,t.*
from
(
SELECT
spi.product_image_id,
spi.product_id,
spi.product_name,
spi.store_id,
lpi. merged_image_url,
lp.thumb,
lp.id,
lp.name
FROM
shop_product_image spi
INNER JOIN
library_product lp ON
spi.product_short_name = lp.product_short_name
LEFT JOIN
(
SELECT
product_id,
GROUP_CONCAT(image_url SEPARATOR ',') AS merged_image_url
FROM
library_product_image
WHERE
is_main = '0'
GROUP BY
product_id
) lpi ON
lp.id = lpi.product_id
WHERE
spi.product_from = '1005'
AND spi.item_image_default = '1'
<![CDATA[ AND lp.product_short_name <> '' ]]>
)t
)temp
where
temp.rn = 1 and temp.store_id=#{storeId} limit #{offset},#{limit}
</sql>
<select id="mappingByProductNameCount" resultType="java.lang.Integer">
select count(1) from shop_image_mapping_temp where store_id=#{storeId}
</select>
<sql id="mappingByProductName">
select product_image_id,
product_id,
product_name,
store_id,
merged_image_url,
thumb,name
from shop_image_mapping_temp
where store_id=#{storeId} limit #{offset},#{limit}
</sql>
</mapper>

View File

@ -0,0 +1,33 @@
alter table shop_product_image add `product_name` varchar(100) DEFAULT '' COMMENT '产品名称同步数据用';
alter table shop_product_image add `product_number` varchar(50) DEFAULT '' COMMENT '商品货号同步数据用';
alter table shop_product_image add `product_short_name` varchar(100) DEFAULT '' COMMENT '商品简称,作为匹配关键字';
alter table library_product add `product_short_name` varchar(100) DEFAULT '' COMMENT '商品简称,作为匹配关键字';
alter table shop_product_base add `product_short_name` varchar(100) DEFAULT '' COMMENT '商品简称,作为匹配关键字';
alter table shop_product_image add `product_from` varchar(5) DEFAULT '' COMMENT '商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅;同步数据匹配';
alter table shop_product_image add index `index_sproduct_short_name` (`product_short_name`) USING BTREE;
alter table library_product add index `index_product_short_name` (`product_short_name`) USING BTREE;
alter table shop_product_base add index `index_product_short_name` (`product_short_name`) USING BTREE;
alter table shop_product_image add index `index_product_from` (`product_from`) USING BTREE;
CREATE INDEX idx_shop_product_filter ON shop_product_image(product_from, item_image_default) USING BTREE;
CREATE TABLE shop_image_mapping_temp (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '临时表id',
`product_image_id` bigint unsigned DEFAULT NULL COMMENT '商品图片编号',
`product_id` bigint unsigned DEFAULT 0 COMMENT '产品编号:product_id-color_id',
`product_name` varchar(100) DEFAULT '' COMMENT '产品名称同步数据用',
`store_id` int unsigned DEFAULT NULL COMMENT '店铺编号',
`merged_image_url` text COMMENT '合并后的图片URL',
`name` varchar(255) DEFAULT '' COMMENT '图库商品名',
`thumb` varchar(512) DEFAULT '' COMMENT '主图',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时',
PRIMARY KEY (`id`),
KEY `index_product_name` (`product_name`) USING BTREE,
KEY `index_name` (`name`) USING BTREE,
KEY `index_store_id` (`store_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品图片映射临时表';