From b030051f42465d616987f0cea54a58b3080e22b1 Mon Sep 17 00:00:00 2001 From: liujiang <569804566@qq.com> Date: Sat, 11 Oct 2025 14:57:50 +0800 Subject: [PATCH] =?UTF-8?q?master=EF=BC=9A=E7=B3=BB=E7=BB=9F=E8=B0=83?= =?UTF-8?q?=E4=BC=98=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xkt/migartion/GtAndFhbBizController.java | 433 +++++++----------- .../java/com/ruoyi/quartz/task/XktTask.java | 5 - 2 files changed, 160 insertions(+), 278 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java index d92382941..3612d4301 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java @@ -1,5 +1,12 @@ package com.ruoyi.web.controller.xkt.migartion; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.json.JSONUtil; +import co.elastic.clients.elasticsearch.core.BulkResponse; +import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; +import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; @@ -11,6 +18,8 @@ import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.framework.es.EsClientWrapper; +import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO; import com.ruoyi.web.controller.xkt.migartion.vo.GtAndFHBCompareDownloadVO; import com.ruoyi.web.controller.xkt.migartion.vo.GtAndFHBInitVO; import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbCusDiscountVO; @@ -20,11 +29,21 @@ import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbProdVO; import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtCateVO; import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtProdSkuVO; import com.ruoyi.xkt.domain.*; +import com.ruoyi.xkt.dto.es.ESProductDTO; +import com.ruoyi.xkt.dto.picture.ProductPicSyncDTO; +import com.ruoyi.xkt.dto.picture.ProductPicSyncResultDTO; +import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdMinPriceDTO; +import com.ruoyi.xkt.dto.storeProduct.StoreProdDTO; +import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileDTO; +import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileResDTO; import com.ruoyi.xkt.enums.EProductStatus; +import com.ruoyi.xkt.enums.FileType; import com.ruoyi.xkt.enums.ListingType; import com.ruoyi.xkt.mapper.*; +import com.ruoyi.xkt.service.IPictureService; import com.ruoyi.xkt.service.shipMaster.IShipMasterService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; @@ -35,6 +54,7 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; import java.net.URLEncoder; import java.time.LocalDate; import java.util.*; @@ -46,6 +66,7 @@ import java.util.stream.Collectors; * * @author ruoyi */ +@Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/rest/v1/gt-fhb") @@ -64,7 +85,9 @@ public class GtAndFhbBizController extends BaseController { final StoreProductServiceMapper prodSvcMapper; final StoreProductCategoryAttributeMapper prodCateAttrMapper; final SysProductCategoryMapper prodCateMapper; - + final StoreProductFileMapper storeProdFileMapper; + final EsClientWrapper esClientWrapper; + final IPictureService pictureService; // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 @@ -72,29 +95,6 @@ public class GtAndFhbBizController extends BaseController { // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 - @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @PostMapping("/sync-es/{storeId}") - public void syncToEs(@PathVariable("storeId") Long storeId) { - // 同步主图 到 图搜 服务器 - - // TODO 上传到ES之后还需要确认 - // TODO 上传到ES之后还需要确认 - // TODO 上传到ES之后还需要确认 - - } - - @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @PostMapping("/sync-pic/{storeId}") - public void syncToPicSearch(@PathVariable("storeId") Long storeId) { - // 同步主图 到 图搜 服务器 - - // TODO 上传到图搜服务器之后还要确认 - // TODO 上传到图搜服务器之后还要确认 - // TODO 上传到图搜服务器之后还要确认 - - } - - /** * step1 */ @@ -348,15 +348,13 @@ public class GtAndFhbBizController extends BaseController { .eq(StoreColor::getStoreId, initVO.getStoreId()).eq(StoreColor::getDelFlag, Constants.UNDELETED)); Map storeColorMap = storeColorList.stream().collect(Collectors.toMap(StoreColor::getColorName, x -> x, (v1, v2) -> v2)); + // TODO 临时处理,10-11之后的数据 // TODO 临时处理,10-11之后的数据 // TODO 临时处理,10-11之后的数据 storeProdList = storeProdList.stream().filter(x -> x.getCreateTime().after(DateUtils.parseDate("2025-10-11 00:00:00"))).collect(Collectors.toList()); - - - Map> multiSaleSameGoMap = new HashMap<>(); Map> multiOffSaleSameGoMap = new HashMap<>(); Map> multiSameFhbMap = new HashMap<>(); @@ -464,6 +462,7 @@ public class GtAndFhbBizController extends BaseController { List storeCusList = this.storeCusMapper.selectList(new LambdaQueryWrapper() .eq(StoreCustomer::getStoreId, initVO.getStoreId()).eq(StoreCustomer::getDelFlag, Constants.UNDELETED)); + // TODO 临时处理,10-11之后的数据 // TODO 临时处理,10-11之后的数据 // TODO 临时处理,10-11之后的数据 @@ -534,259 +533,102 @@ public class GtAndFhbBizController extends BaseController { } /** - * 步骤1: 准备数据,新建颜色; - * 步骤2: GT 和 FHB 货号对应关系,然后直接copy 对应的属性关系 - * // a. 商品与颜色对应关系 - * // b. 商品颜色尺码 + 价格 对应关系 - * // c. 库存初始化 - * // d. 服务承诺初始化 - * // e. 类目属性初始化 - * 步骤3: 准备数据,新建客户 - * 步骤4: 客户与货号的优惠关系 - * 步骤5: 批量创建数据到ES服务器 + * step5 */ -/* @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @PutMapping("/init") - @Transactional - public void initToDB(@Validated @RequestBody GtAndFHBInitVO initVO) { - // 去掉可能的空格 - initVO.setExcludeArtNoList(initVO.getExcludeArtNoList().stream().map(String::trim).collect(Collectors.toList())); - Optional.ofNullable(this.storeMapper.selectOne(new LambdaQueryWrapper() - .eq(Store::getId, initVO.getStoreId()).eq(Store::getDelFlag, Constants.UNDELETED))) - .orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR)); - // 步骤1: 准备数据,新建颜色 - Map storeColorMap = this.initStoreColorList(initVO.getStoreId(), initVO.getSupplierId()); - // 步骤2: GT 和 FHB 货号对应关系,然后直接copy 对应的属性关系 - // a. 商品与颜色对应关系 - // b. 商品颜色尺码 + 价格 对应关系 - // c. 库存初始化 - // d. 服务承诺初始化 - // e. 类目属性初始化 - this.init(initVO, storeColorMap); - - // 步骤x: 查看有哪些货号价格是有多个的,单独设置差异的价格 - - // 步骤5: 批量创建数据到ES服务器 - - } - - private R init(GtAndFHBInitVO initVO, Map storeColorMap) { - // 步骤2: GT 和 FHB 货号对应关系,然后直接copy 对应的属性关系 - // a. 商品与颜色对应关系 - // b. 商品颜色尺码 + 价格 对应关系 - // c. 库存初始化 - // d. 服务承诺初始化 - // e. 类目属性初始化 - Map> multiSaleSameGoMap = new HashMap<>(); - Map> multiOffSaleSameGoMap = new HashMap<>(); - Map> multiSameFhbMap = new HashMap<>(); - List gtSaleBasicList = ObjectUtils.defaultIfNull(redisCache - .getCacheObject(CacheConstants.MIGRATION_GT_SALE_BASIC_KEY + initVO.getUserId()), new ArrayList<>()); - // 查看gt 在售的商品 这边有多少相似的货号 - gtSaleBasicList.stream().map(GtProdSkuVO::getArticle_number).distinct() - // 过滤掉需要特殊处理的货号 - .filter(article_number -> !initVO.getExcludeArtNoList().contains(article_number)) - .forEach(article_number -> { - // 只保留核心连续的数字,去除其他所有符号 - String cleanArtNo = this.extractCoreArticleNumber(article_number); - List existList = multiSaleSameGoMap.containsKey(cleanArtNo) ? multiSaleSameGoMap.get(cleanArtNo) : new ArrayList<>(); - existList.add(article_number); - multiSaleSameGoMap.put(cleanArtNo, existList); - }); - - // 查看gt 下架的商品有多少相似的货号 - List gtOffSaleBasicList = ObjectUtils.defaultIfNull(redisCache - .getCacheObject(CacheConstants.MIGRATION_GT_OFF_SALE_BASIC_KEY + initVO.getUserId()), new ArrayList<>()); - gtOffSaleBasicList.stream().map(GtProdSkuVO::getArticle_number).distinct().forEach(article_number -> { - // 只保留核心连续的数字,去除其他所有符号 - String cleanArtNo = this.extractCoreArticleNumber(article_number); - List existList = multiOffSaleSameGoMap.containsKey(cleanArtNo) ? multiOffSaleSameGoMap.get(cleanArtNo) : new ArrayList<>(); - existList.add(article_number); - multiOffSaleSameGoMap.put(cleanArtNo, existList); - }); - - // 查看Fhb 这边有多少相似的货号 - List fhbProdList = ObjectUtils.defaultIfNull(redisCache - .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_PROD_KEY + initVO.getSupplierId()), new ArrayList<>()); - // Fhb按照颜色分类 - Map> fhbProdGroupMap = fhbProdList.stream().collect(Collectors.groupingBy(FhbProdVO.SMIVO::getArtNo)); - fhbProdList.stream().map(FhbProdVO.SMIVO::getArtNo).distinct() - // 过滤掉需要特殊处理的货号 - .filter(artNo -> !initVO.getExcludeArtNoList().contains(artNo)) - .forEach(artNo -> { - // 只保留核心连续的数字,去除其他所有符号 - String cleanArtNo = this.extractCoreArticleNumber(artNo); - List existList = multiSameFhbMap.containsKey(cleanArtNo) ? multiSameFhbMap.get(cleanArtNo) : new ArrayList<>(); - existList.add(artNo); - multiSameFhbMap.put(cleanArtNo, existList); - }); - - // gt按照货号分组 - Map> gtSaleGroupMap = gtSaleBasicList.stream().collect(Collectors.groupingBy(GtProdSkuVO::getArticle_number)); - - // GT分类 - List cacheList = ObjectUtils.defaultIfNull(redisCache - .getCacheObject(CacheConstants.MIGRATION_GT_SALE_CATE_KEY + initVO.getUserId()), new ArrayList<>()); + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @PostMapping("/sync-es/{storeId}") + public void syncToEs(@PathVariable("storeId") Long storeId) { + // 将公共的商品同步到ES + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, storeId)); + if (CollectionUtils.isEmpty(storeProdList)) { + return; + } + final List storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList()); + // 获取所有的商品的第一张主图 + List mainPicList = this.storeProdFileMapper.selectMainPic(storeProdIdList); + // 所有的商品主图map + Map> mainPicMap = mainPicList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue())) + .collect(Collectors.groupingBy(StoreProdFileResDTO::getStoreProdId, Collectors.mapping(StoreProdFileResDTO::getFileUrl, Collectors.toList()))); + // 第一张商品主图map + Map firstMainPicMap = mainPicList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue())) + .filter(x -> Objects.equals(x.getOrderNum(), Constants.ORDER_NUM_1)).collect(Collectors + .toMap(StoreProdFileResDTO::getStoreProdId, x -> x)); + // 主图视频map + Map mainVideoMap = mainPicList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC_VIDEO.getValue())) + .collect(Collectors.toMap(StoreProdFileResDTO::getStoreProdId, x -> true)); + // 所有的分类 List prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper() .eq(SysProductCategory::getDelFlag, Constants.UNDELETED)); - Map dbCateNameMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getName, SysProductCategory::getId)); - // GT商品分类和步橘分类映射 - Map cateRelationMap = new HashMap<>(); - cacheList.forEach(gtCate -> { - final Long cateId = Optional.ofNullable(dbCateNameMap.get(gtCate.getName())).orElseThrow(() -> new ServiceException("GT分类不存在!", HttpStatus.ERROR)); - cateRelationMap.put(gtCate.getId(), cateId); - }); - - System.err.println("============ 两边系统“一致”的货号 ============"); - // 清洗后,相同货号映射 - Set commonArtNos = new HashSet<>(multiSaleSameGoMap.keySet()); - commonArtNos.retainAll(multiSameFhbMap.keySet()); - // 待导入的商品 - List storeProdList = new ArrayList<>(); - // 当天 - final Date voucherDate = java.sql.Date.valueOf(LocalDate.now()); - // 所有商品的类目属性map key gt的product_id value StoreProductCategoryAttribute - Map prodAttrMap = new HashMap<>(); - commonArtNos.forEach(cleanArtNo -> { - // 获取GT匹配的商品中的第一个商品 - List gtMatchSkuList = this.getGtFirstSku(multiSaleSameGoMap, gtSaleGroupMap, cleanArtNo); - // 初始化档口商品 - StoreProduct storeProd = new StoreProduct().setStoreId(initVO.getStoreId()).setProdCateId(cateRelationMap.get(gtMatchSkuList.get(0).getCategory_nid())) - .setProdArtNum(gtMatchSkuList.get(0).getArticle_number()).setProdTitle(gtMatchSkuList.get(0).getCharacters()).setListingWay(ListingType.RIGHT_NOW.getValue()) - .setVoucherDate(voucherDate).setProdStatus(EProductStatus.ON_SALE.getValue()).setRecommendWeight(0L).setSaleWeight(0L).setPopularityWeight(0L); - // 提前设置档口商品的类目属性 - this.preMatchAttr(gtMatchSkuList.get(0).getProduct_id(), initVO.getUserId(), prodAttrMap); - storeProdList.add(storeProd); - }); - this.storeProdMapper.insert(storeProdList); - - // 商品所有颜色 尺码 颜色库存初始化 - List prodColorList = new ArrayList<>(); - List prodColorSizeList = new ArrayList<>(); - List prodSvcList = new ArrayList<>(); - List prodAttrList = new ArrayList<>(); - storeProdList.forEach(storeProd -> { - // 获取clearArtNo - String clearArtNo = this.extractCoreArticleNumber(storeProd.getProdArtNum()); - // FHB匹配的货号 - List fhbMatchArtNoList = multiSameFhbMap.get(clearArtNo); - // 获取GT匹配的商品sku列表 - List gtMatchSkuList = this.getGtFirstSku(multiSaleSameGoMap, gtSaleGroupMap, clearArtNo); - // 当前货号在GT的所有尺码,作为标准尺码 - List gtStandardSizeList = gtMatchSkuList.stream().map(sku -> (int) Math.floor(Double.parseDouble(sku.getSize()))).collect(Collectors.toList()); - AtomicInteger orderNum = new AtomicInteger(); - fhbMatchArtNoList.forEach(fhbArtNo -> { - List fhbMatchSkuList = fhbProdGroupMap.get(fhbArtNo); - for (int i = 0; i < fhbMatchSkuList.size(); i++) { - StoreColor storeColor = Optional.ofNullable(storeColorMap.get(fhbMatchSkuList.get(i).getColor())) - .orElseThrow(() -> new ServiceException("没有FHB商品颜色!" + fhbArtNo, HttpStatus.ERROR)); - // 该商品的颜色 - prodColorList.add(new StoreProductColor().setStoreId(storeProd.getStoreId()).setStoreProdId(storeProd.getId()).setOrderNum(orderNum.addAndGet(1)) - .setColorName(storeColor.getColorName()).setStoreColorId(storeColor.getId()).setProdStatus(EProductStatus.ON_SALE.getValue())); - // 该颜色所有的尺码 - for (int j = 0; j < Constants.SIZE_LIST.size(); j++) { - // FHB系统条码前缀 - final String otherSnPrefix = fhbMatchSkuList.get(i).getSupplierId() - + String.format("%05d", fhbMatchSkuList.get(i).getSupplierSkuId()) + Constants.SIZE_LIST.get(j); - prodColorSizeList.add(new StoreProductColorSize().setSize(Constants.SIZE_LIST.get(j)).setStoreColorId(storeColor.getId()) - .setStoreProdId(storeProd.getId()).setStandard(gtStandardSizeList.contains(Constants.SIZE_LIST.get(j)) ? 1 : 0) - // 销售价格以FHB价格为准 - .setPrice(fhbMatchSkuList.get(i).getSalePrice()) - .setOtherSnPrefix(otherSnPrefix).setNextSn(0)); - } - } - }); - - // 初始化商品服务承诺 - prodSvcList.add(new StoreProductService().setStoreProdId(storeProd.getId()).setCustomRefund("0") - .setThirtyDayRefund("0").setOneBatchSale("1").setRefundWithinThreeDay("0")); - - // 初始化商品的类目属性 - StoreProductCategoryAttribute cateAttr = Optional.ofNullable(prodAttrMap.get(gtMatchSkuList.get(0).getProduct_id())) - .orElseThrow(() -> new ServiceException("没有GT商品类目属性!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); - cateAttr.setStoreId(storeProd.getStoreId()).setStoreProdId(storeProd.getId()); - prodAttrList.add(cateAttr); - }); - // 插入商品颜色及颜色对应的尺码,档口服务承诺 - this.prodColorMapper.insert(prodColorList); - prodColorSizeList.sort(Comparator.comparing(StoreProductColorSize::getStoreProdId).thenComparing(StoreProductColorSize::getSize)); - this.prodColorSizeMapper.insert(prodColorSizeList); - this.prodSvcMapper.insert(prodSvcList); - this.prodCateAttrMapper.insert(prodAttrList); - - // 还要更新步橘系统的条码前缀 - prodColorSizeList.forEach(x -> x.setSnPrefix(initVO.getStoreId() + String.format("%08d", x.getId()))); - this.prodColorSizeMapper.updateById(prodColorSizeList); - - // 步骤3: 准备数据,新建客户 - List storeCusList = this.initStoreCusList(initVO); - - // 步骤4: 客户与货号的优惠关系 - this.initStoreCusProdDiscAndProdStock(initVO, storeProdList, storeCusList, prodColorList, multiSameFhbMap); - - return R.ok(); - }*/ - - - /** - * 新建档口客户对应产品的优惠 - * - * @param initVO 入参 - * @param storeProdList 档口商品列表 - * @param storeCusList 档口客户列表 - * @param prodColorList 商品颜色列表 - * @param multiSameFhbMap 步橘货号和FHB货号对应关系 - */ - private void initStoreCusProdDiscAndProdStock(GtAndFHBInitVO initVO, List storeProdList, List storeCusList, - List prodColorList, Map> multiSameFhbMap) { - // 从redis中获取客户优惠数据 - List fhbCusDiscCacheList = ObjectUtils.defaultIfNull(redisCache - .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_CUS_DISCOUNT_KEY + initVO.getSupplierId()), new ArrayList<>()); - if (CollectionUtils.isEmpty(fhbCusDiscCacheList)) { - throw new ServiceException("fhb供应商客户优惠列表为空!" + initVO.getSupplierId(), HttpStatus.ERROR); + Map prodCateMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getId, x -> x)); + // 获取当前商品最低价格 + Map prodMinPriceMap = this.prodColorSizeMapper.selectStoreProdMinPriceList(storeProdIdList).stream().collect(Collectors + .toMap(StoreProdMinPriceDTO::getStoreProdId, StoreProdMinPriceDTO::getPrice)); + // 档口商品的属性map + Map cateAttrMap = this.prodCateAttrMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).in(StoreProductCategoryAttribute::getStoreProdId, storeProdIdList)) + .stream().collect(Collectors.toMap(StoreProductCategoryAttribute::getStoreProdId, x -> x)); + // 档口商品对应的档口 + Map storeMap = this.storeMapper.selectList(new LambdaQueryWrapper().eq(Store::getDelFlag, Constants.UNDELETED) + .in(Store::getId, storeProdList.stream().map(StoreProduct::getStoreId).collect(Collectors.toList()))) + .stream().collect(Collectors.toMap(Store::getId, x -> x)); + List esProductDTOList = new ArrayList<>(); + for (StoreProduct product : storeProdList) { + final SysProductCategory cate = prodCateMap.get(product.getProdCateId()); + final SysProductCategory parCate = ObjectUtils.isEmpty(cate) ? null : prodCateMap.get(cate.getParentId()); + final Store store = storeMap.get(product.getStoreId()); + final StoreProdFileResDTO mainPic = firstMainPicMap.get(product.getId()); + final BigDecimal prodMinPrice = prodMinPriceMap.get(product.getId()); + final StoreProductCategoryAttribute cateAttr = cateAttrMap.get(product.getId()); + final Boolean hasVideo = mainVideoMap.getOrDefault(product.getId(), Boolean.FALSE); + ESProductDTO esProductDTO = new ESProductDTO().setStoreProdId(product.getId().toString()).setProdArtNum(product.getProdArtNum()) + .setHasVideo(hasVideo).setProdCateId(product.getProdCateId().toString()).setCreateTime(DateUtils.getTime()) + .setProdCateName(ObjectUtils.isNotEmpty(cate) ? cate.getName() : "") + .setSaleWeight("0").setRecommendWeight("0").setPopularityWeight("0") + .setMainPicUrl(ObjectUtils.isNotEmpty(mainPic) ? mainPic.getFileUrl() : "") + .setMainPicName(ObjectUtils.isNotEmpty(mainPic) ? mainPic.getFileName() : "") + .setMainPicSize(ObjectUtils.isNotEmpty(mainPic) ? mainPic.getFileSize() : BigDecimal.ZERO) + .setParCateId(ObjectUtils.isNotEmpty(parCate) ? parCate.getId().toString() : "") + .setParCateName(ObjectUtils.isNotEmpty(parCate) ? parCate.getName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(prodMinPrice) ? prodMinPrice.toString() : "") + .setSeason(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getSuitableSeason() : "") + .setProdStatus(product.getProdStatus().toString()) + .setStoreId(product.getStoreId().toString()) + .setStoreName(ObjectUtils.isNotEmpty(store) ? store.getStoreName() : "") + .setStyle(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getStyle() : "") + .setTags(ObjectUtils.isNotEmpty(cateAttr) ? Collections.singletonList(cateAttr.getStyle()) : new ArrayList<>()) + .setProdTitle(product.getProdTitle()); + esProductDTOList.add(esProductDTO); } - List fhbStockCacheList = redisCache - .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_PROD_STOCK_KEY + initVO.getSupplierId()); - if (CollectionUtils.isEmpty(fhbStockCacheList)) { - throw new ServiceException("fhb供应商商品库存列表为空!" + initVO.getSupplierId(), HttpStatus.ERROR); + // 构建批量操作请求 + List bulkOperations = new ArrayList<>(); + for (ESProductDTO esProductDTO : esProductDTOList) { + BulkOperation bulkOperation = new BulkOperation.Builder() + .index(i -> i.id(esProductDTO.getStoreProdId()).index(Constants.ES_IDX_PRODUCT_INFO).document(esProductDTO)) + .build(); + bulkOperations.add(bulkOperation); } - // FHB 货号颜色优惠对应关系 - Map>> fhbCusDiscGroupMap = fhbCusDiscCacheList.stream().collect(Collectors - .groupingBy(FhbCusDiscountVO.SMCDRecordVO::getArtNo, Collectors.groupingBy(FhbCusDiscountVO.SMCDRecordVO::getColor))); - // FHB 货号颜色库存对应关系 - Map> fhbStockGroupMap = fhbStockCacheList.stream().collect(Collectors - .groupingBy(FhbProdStockVO.SMPSRecordVO::getArtNo, Collectors.toMap(FhbProdStockVO.SMPSRecordVO::getColor, x -> x))); - // 步橘系统商品所有颜色maps - Map> prodColorGroupMap = prodColorList.stream().collect(Collectors - .groupingBy(StoreProductColor::getStoreProdId, Collectors.toMap(StoreProductColor::getColorName, x -> x))); - // 步橘系统客户名称map - Map buJuStoreCusMap = storeCusList.stream().collect(Collectors.toMap(StoreCustomer::getCusName, x -> x)); - List prodCusDiscList = new ArrayList<>(); - List prodStockList = new ArrayList<>(); - // 依次遍历商品列表,找到货号和FHB货号对应关系,然后用颜色进行匹配,建立客户优惠关系 - storeProdList.forEach(storeProd -> { - final String cleanArtNo = this.extractCoreArticleNumber(storeProd.getProdArtNum()); - // 当前商品颜色列表 key 颜色中文名称 - Map buJuProdColorMap = Optional.ofNullable(prodColorGroupMap.get(storeProd.getId())).orElseThrow(() -> new ServiceException("没有商品颜色!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); - // 根据步橘货号 找到FHB对应的货号,可能是列表 - List fhbAtrNoList = Optional.ofNullable(multiSameFhbMap.get(cleanArtNo)).orElseThrow(() -> new ServiceException("没有FHB货号!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); - fhbAtrNoList.forEach(fhbAtrNo -> { - // 处理档口客户商品优惠 - this.handleCusDisc(fhbAtrNo, fhbCusDiscGroupMap, buJuProdColorMap, buJuStoreCusMap, storeProd.getStoreId(), storeProd.getId(), prodCusDiscList); - // 处理档口商品库存 - this.handleProdStock(fhbAtrNo, fhbStockGroupMap, buJuProdColorMap, storeProd.getStoreId(), storeProd.getId(), storeProd.getProdArtNum(), prodStockList); - }); + // 执行批量插入 + try { + BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(Constants.ES_IDX_PRODUCT_INFO).operations(bulkOperations)); + log.info("批量新增到 ES 成功,共处理 {} 条记录", response.items().size()); + log.info("批量新增到 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList())); + } catch (Exception e) { + log.error("批量新增到 ES 失败", e); + } + // 依次同步主图到图搜列表 + storeProdList.forEach(x -> { + List mainPicUrlList = mainPicMap.get(x.getId()); + if (CollUtil.isEmpty(mainPicUrlList)) { + return; + } + this.sync2ImgSearchServer(x.getId(), mainPicUrlList); }); - - // 档口客户优惠 - this.storeCusProdDiscMapper.insert(prodCusDiscList); - // 档口客户库存 - this.prodStockMapper.insert(prodStockList); - } /** * 处理货号颜色的库存 + * * @param fhbAtrNo * @param fhbStockGroupMap * @param buJuProdColorMap @@ -849,9 +691,8 @@ public class GtAndFhbBizController extends BaseController { * 初始化客户列表 * * @param initVO 入参 - * @return List */ - private List initStoreCusList(GtAndFHBInitVO initVO) { + private void initStoreCusList(GtAndFHBInitVO initVO) { List cacheList = ObjectUtils.defaultIfNull(redisCache .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_CUS_KEY + initVO.getSupplierId()), new ArrayList<>()); if (CollectionUtils.isEmpty(cacheList)) { @@ -863,7 +704,6 @@ public class GtAndFhbBizController extends BaseController { .map(x -> new StoreCustomer().setStoreId(initVO.getStoreId()).setCusName(x.getName())) .collect(Collectors.toList()); this.storeCusMapper.insert(storeCusList); - return storeCusList; } @@ -1043,5 +883,52 @@ public class GtAndFhbBizController extends BaseController { throw new ServiceException("货号格式错误", HttpStatus.ERROR); } + /** + * 组装ES 入参 DTO + * + * @param storeProd 档口商品 + * @param updateDTO 档口商品更新入参 + * @param storeName 档口名称 + * @return + */ + private ESProductDTO getESDTO(StoreProduct storeProd, StoreProdDTO updateDTO, String storeName) { + // 获取第一张主图 + String firstMainPic = updateDTO.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)); + // 是否有主图视频 + boolean hasVideo = updateDTO.getFileList().stream().anyMatch(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC_VIDEO.getValue())); + // 获取上一级分类的分类ID 及 分类名称 + ProdCateDTO parCate = this.prodCateMapper.getParentCate(updateDTO.getProdCateId()); + // 获取当前商品的最低价格 + BigDecimal minPrice = updateDTO.getSizeList().stream().min(Comparator.comparing(StoreProdDTO.SPCSizeDTO::getPrice)) + .map(StoreProdDTO.SPCSizeDTO::getPrice).orElseThrow(() -> new ServiceException("商品价格不存在!", HttpStatus.ERROR)); + // 获取使用季节 + String season = updateDTO.getCateAttr().getSuitableSeason(); + // 获取风格 + String style = updateDTO.getCateAttr().getStyle(); + return BeanUtil.toBean(storeProd, ESProductDTO.class).setHasVideo(hasVideo) + .setProdCateName(updateDTO.getProdCateName()).setSaleWeight("0").setRecommendWeight("0").setPopularityWeight("0") + .setCreateTime(DateUtils.getTime()).setStoreName(storeName).setMainPicUrl(firstMainPic) + .setParCateId(parCate.getProdCateId().toString()).setParCateName(parCate.getName()).setProdPrice(minPrice.toString()) + .setSeason(season).setStyle(style).setTags(Collections.singletonList(style)); + } + + + /** + * 搜图服务同步商品 + * + * @param storeProductId 档口商品ID + * @param picKeys 商品主图列表 + */ + private void sync2ImgSearchServer(Long storeProductId, List picKeys) { + ThreadUtil.execAsync(() -> { + ProductPicSyncResultDTO r = + pictureService.sync2ImgSearchServer(new ProductPicSyncDTO(storeProductId, picKeys)); + log.info("商品图片同步至搜图服务器: id: {}, result: {}", storeProductId, JSONUtil.toJsonStr(r)); + } + ); + } + } diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java index 78386db9f..1f24434ab 100644 --- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/XktTask.java @@ -124,10 +124,6 @@ public class XktTask { final SysDictDataMapper dictDataMapper; final StoreProductColorSizeMapper prodColorSizeMapper; - public void test() throws IOException { - System.err.println("aaa"); - } - /** * 每天执行定时任务 * 每年3月1日、6月1日、9月1日、12月1日执行 生成夏秋冬春标签 @@ -856,7 +852,6 @@ public class XktTask { if (CollectionUtils.isEmpty(unPublicList)) { return; } - System.err.println(unPublicList); final List storeProdIdList = unPublicList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList()); // 获取所有的商品的第一张主图 List mainPicList = this.storeProdFileMapper.selectMainPic(storeProdIdList);