master:系统调优;
parent
802927498b
commit
bad6ee092b
|
|
@ -11,7 +11,6 @@ import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbCusDiscountVO;
|
|||
import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbCusVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbProdStockVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbProdVO;
|
||||
import com.ruoyi.xkt.service.shipMaster.IShipMasterService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
|
@ -33,7 +32,6 @@ import java.util.stream.Collectors;
|
|||
@RequestMapping("/rest/v1/fhb")
|
||||
public class FhbController extends BaseController {
|
||||
|
||||
final IShipMasterService shipMasterService;
|
||||
final RedisCache redisCache;
|
||||
|
||||
/**
|
||||
|
|
@ -130,11 +128,12 @@ public class FhbController extends BaseController {
|
|||
|
||||
/**
|
||||
* step5
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
|
||||
@GetMapping("/error/cus/disc/{supplierId}")
|
||||
public R<CusDiscErrorVO> getErrorCusDisc(@PathVariable Integer supplierId){
|
||||
public R<CusDiscErrorVO> getErrorCusDisc(@PathVariable Integer supplierId) {
|
||||
// 先从redis中获取列表数据
|
||||
List<FhbCusDiscountVO.SMCDRecordVO> cacheList = ObjectUtils.defaultIfNull(redisCache
|
||||
.getCacheObject(CacheConstants.MIGRATION_SUPPLIER_CUS_DISCOUNT_KEY + supplierId), new ArrayList<>());
|
||||
|
|
@ -168,11 +167,9 @@ public class FhbController extends BaseController {
|
|||
}
|
||||
|
||||
|
||||
|
||||
// ======================================================================================================================================
|
||||
|
||||
|
||||
|
||||
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
|
||||
@PostMapping("/colors/cache/{supplierId}")
|
||||
public R<Integer> createColorsCache(@PathVariable Integer supplierId) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import com.ruoyi.xkt.enums.EProductStatus;
|
|||
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;
|
||||
|
|
@ -66,7 +65,6 @@ import static com.ruoyi.common.constant.Constants.WEIGHT_DEFAULT_ZERO;
|
|||
@RequestMapping("/rest/v1/gt-fhb")
|
||||
public class GtAndFhbBizController extends BaseController {
|
||||
|
||||
final IShipMasterService shipMasterService;
|
||||
final RedisCache redisCache;
|
||||
final StoreProductColorMapper prodColorMapper;
|
||||
final StoreProductColorSizeMapper prodColorSizeMapper;
|
||||
|
|
@ -846,7 +844,8 @@ public class GtAndFhbBizController extends BaseController {
|
|||
|
||||
/**
|
||||
* 初始化档口颜色
|
||||
* @param storeId 档口ID
|
||||
*
|
||||
* @param storeId 档口ID
|
||||
* @param supplierId 供应商ID
|
||||
*/
|
||||
private void initStoreColorList(Long storeId, Integer supplierId) {
|
||||
|
|
@ -887,7 +886,4 @@ public class GtAndFhbBizController extends BaseController {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.ruoyi.web.controller.xkt.migartion;
|
||||
|
||||
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;
|
||||
|
|
@ -9,7 +12,10 @@ import com.ruoyi.common.core.domain.R;
|
|||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
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.framework.notice.fs.FsNotice;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYCompareDownloadVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYInitVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtCateVO;
|
||||
|
|
@ -19,11 +25,13 @@ import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyCusImportVO;
|
|||
import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdImportVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdStockVO;
|
||||
import com.ruoyi.xkt.domain.*;
|
||||
import com.ruoyi.xkt.dto.es.ESProductDTO;
|
||||
import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdMinPriceDTO;
|
||||
import com.ruoyi.xkt.enums.EProductStatus;
|
||||
import com.ruoyi.xkt.enums.ListingType;
|
||||
import com.ruoyi.xkt.mapper.*;
|
||||
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;
|
||||
|
|
@ -34,23 +42,26 @@ 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.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.ruoyi.common.constant.Constants.WEIGHT_DEFAULT_ZERO;
|
||||
|
||||
/**
|
||||
* Compare 相关 处理主要是 匹配非常贴近的数据
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/rest/v1/gt-ty/t2")
|
||||
public class GtAndTyBiz2Controller extends BaseController {
|
||||
|
||||
final IShipMasterService shipMasterService;
|
||||
final RedisCache redisCache;
|
||||
final StoreProductColorMapper prodColorMapper;
|
||||
final StoreProductColorSizeMapper prodColorSizeMapper;
|
||||
|
|
@ -63,34 +74,8 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
final StoreProductServiceMapper prodSvcMapper;
|
||||
final StoreProductCategoryAttributeMapper prodCateAttrMapper;
|
||||
final SysProductCategoryMapper prodCateMapper;
|
||||
|
||||
|
||||
// TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍
|
||||
// TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍
|
||||
// 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 上传到图搜服务器之后还要确认
|
||||
|
||||
}
|
||||
final EsClientWrapper esClientWrapper;
|
||||
final FsNotice fsNotice;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -357,15 +342,6 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* step4
|
||||
*/
|
||||
|
|
@ -381,33 +357,43 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
List<StoreCustomer> storeCusList = this.storeCusMapper.selectList(new LambdaQueryWrapper<StoreCustomer>()
|
||||
.eq(StoreCustomer::getStoreId, initVO.getStoreId()).eq(StoreCustomer::getDelFlag, Constants.UNDELETED));
|
||||
|
||||
Map<String, List<String>> multiSameTyMap = new HashMap<>();
|
||||
// 查看TY 这边有多少相似的货号
|
||||
List<TyProdImportVO> tyProdList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId());
|
||||
tyProdList.stream().map(TyProdImportVO::getProdArtNum).distinct()
|
||||
.forEach(artNo -> {
|
||||
// 只保留核心连续的数字,去除其他所有符号
|
||||
String cleanArtNo = this.extractCoreArticleNumber(artNo);
|
||||
if (CollectionUtils.isEmpty(initVO.getExcludeArtNoList()) || !initVO.getExcludeArtNoList().contains(cleanArtNo)) {
|
||||
List<String> existList = multiSameTyMap.containsKey(cleanArtNo) ? multiSameTyMap.get(cleanArtNo) : new ArrayList<>();
|
||||
existList.add(artNo);
|
||||
multiSameTyMap.put(cleanArtNo, existList);
|
||||
}
|
||||
});
|
||||
// 处理的思路,以GT为主,根据GT的货号 去匹配TY的货号,有些档口写的比较规范,这种就比较好处理
|
||||
List<GtProdSkuVO> gtOnSaleList = ObjectUtils.defaultIfNull(redisCache.getCacheObject(CacheConstants.MIGRATION_GT_SALE_BASIC_KEY + initVO.getUserId()), new ArrayList<>());
|
||||
// gt所有在售的货号列表
|
||||
List<String> gtArtNoList = gtOnSaleList.stream().map(GtProdSkuVO::getArticle_number).map(String::trim).distinct().collect(Collectors.toList());
|
||||
|
||||
// TY商品缓存
|
||||
List<TyProdImportVO> cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId());
|
||||
if (CollectionUtils.isEmpty(cacheList)) {
|
||||
// 找到TY对应的商品
|
||||
List<TyProdImportVO> tyProdList = ObjectUtils.defaultIfNull(redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()), new ArrayList<>());
|
||||
if (CollectionUtils.isEmpty(tyProdList)) {
|
||||
throw new ServiceException("TY商品列表为空", HttpStatus.ERROR);
|
||||
}
|
||||
// ty货号正在生效的颜色map,因为客户优惠有些是删除的颜色,需要通过这里去过滤
|
||||
Map<String, Set<String>> tyExistArtNoColorMap = cacheList.stream().collect(Collectors
|
||||
Map<String, Set<String>> tyExistArtNoColorMap = tyProdList.stream().collect(Collectors
|
||||
.groupingBy(TyProdImportVO::getProdArtNum, Collectors.mapping(TyProdImportVO::getColorName, Collectors.toSet())));
|
||||
// TY货号下颜色的map
|
||||
Map<String, String> tyArtNoColorMap = tyProdList.stream().collect(Collectors.groupingBy(TyProdImportVO::getProdArtNum,
|
||||
Collectors.collectingAndThen(Collectors.mapping(TyProdImportVO::getColorName, Collectors.toList()),
|
||||
list -> "(" + list.stream().distinct().collect(Collectors.joining(",")) + ")")));
|
||||
|
||||
// GT和TY匹配的货号map
|
||||
Map<String, List<String>> gtMatchTyArtNoMap = new HashMap<>();
|
||||
// 以GT为准在,找TY匹配的货号
|
||||
gtArtNoList.forEach(gtOnSaleArtNo -> tyArtNoColorMap.forEach((tyArtNo, tyArtNoColorStr) -> {
|
||||
if (tyArtNo.contains(gtOnSaleArtNo)) {
|
||||
List<String> existMatchArtNoList = gtMatchTyArtNoMap.getOrDefault(gtOnSaleArtNo, new ArrayList<>());
|
||||
existMatchArtNoList.add(tyArtNo);
|
||||
gtMatchTyArtNoMap.put(gtOnSaleArtNo, existMatchArtNoList);
|
||||
}
|
||||
}));
|
||||
|
||||
// 从redis中获取已存在的客户优惠数据
|
||||
List<TyCusDiscImportVO> tyCusDiscCacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_DISCOUNT_KEY + initVO.getUserId());
|
||||
if (CollectionUtils.isEmpty(tyCusDiscCacheList)) {
|
||||
throw new ServiceException("ty供应商客户优惠列表为空!" + initVO.getUserId(), HttpStatus.ERROR);
|
||||
}
|
||||
// 增加一重保险,客户优惠必须大于0
|
||||
tyCusDiscCacheList = tyCusDiscCacheList.stream().filter(x -> x.getDiscount() > 0).collect(Collectors.toList());
|
||||
|
||||
// 从redis中获取已存在的商品库存数据
|
||||
List<TyProdStockVO> tyStockList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_STOCK_KEY + initVO.getUserId());
|
||||
if (CollectionUtils.isEmpty(tyStockList)) {
|
||||
|
|
@ -428,11 +414,10 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
List<StoreProductStock> prodStockList = new ArrayList<>();
|
||||
// 依次遍历商品列表,找到货号和FHB货号对应关系,然后用颜色进行匹配,建立客户优惠关系
|
||||
storeProdList.forEach(storeProd -> {
|
||||
final String cleanArtNo = this.extractCoreArticleNumber(storeProd.getProdArtNum());
|
||||
// 当前商品颜色列表 key 颜色中文名称
|
||||
Map<String, StoreProductColor> buJuProdColorMap = Optional.ofNullable(prodColorGroupMap.get(storeProd.getId())).orElseThrow(() -> new ServiceException("没有商品颜色!" + storeProd.getProdArtNum(), HttpStatus.ERROR));
|
||||
// 根据步橘货号 找到TY对应的货号,可能是列表
|
||||
List<String> tyAtrNoList = Optional.ofNullable(multiSameTyMap.get(cleanArtNo)).orElseThrow(() -> new ServiceException("没有TY货号!" + storeProd.getProdArtNum(), HttpStatus.ERROR));
|
||||
List<String> tyAtrNoList = Optional.ofNullable(gtMatchTyArtNoMap.get(storeProd.getProdArtNum())).orElseThrow(() -> new ServiceException("没有TY货号!" + storeProd.getProdArtNum(), HttpStatus.ERROR));
|
||||
// 处理档口商品库存
|
||||
this.handleProdStock(tyAtrNoList, tyProdStockMap, buJuProdColorMap, storeProd.getStoreId(), storeProd.getId(), storeProd.getProdArtNum(), prodStockList);
|
||||
|
||||
|
|
@ -451,6 +436,88 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* step5
|
||||
*/
|
||||
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
|
||||
@PostMapping("/sync-es/{storeId}")
|
||||
public R<Integer> syncToEs(@PathVariable("storeId") Long storeId) {
|
||||
// 将公共的商品同步到ES
|
||||
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
|
||||
.eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, storeId));
|
||||
if (CollectionUtils.isEmpty(storeProdList)) {
|
||||
return R.fail();
|
||||
}
|
||||
final List<String> storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList());
|
||||
// 所有的分类
|
||||
List<SysProductCategory> prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper<SysProductCategory>()
|
||||
.eq(SysProductCategory::getDelFlag, Constants.UNDELETED));
|
||||
Map<Long, SysProductCategory> prodCateMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getId, x -> x));
|
||||
// 获取当前商品最低价格
|
||||
Map<Long, BigDecimal> prodMinPriceMap = this.prodColorSizeMapper.selectStoreProdMinPriceList(storeProdIdList).stream().collect(Collectors
|
||||
.toMap(StoreProdMinPriceDTO::getStoreProdId, StoreProdMinPriceDTO::getPrice));
|
||||
// 档口商品的属性map
|
||||
Map<Long, StoreProductCategoryAttribute> cateAttrMap = this.prodCateAttrMapper.selectList(new LambdaQueryWrapper<StoreProductCategoryAttribute>()
|
||||
.eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).in(StoreProductCategoryAttribute::getStoreProdId, storeProdIdList))
|
||||
.stream().collect(Collectors.toMap(StoreProductCategoryAttribute::getStoreProdId, x -> x));
|
||||
// 档口商品对应的档口
|
||||
Map<Long, Store> storeMap = this.storeMapper.selectList(new LambdaQueryWrapper<Store>().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<ESProductDTO> 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 BigDecimal prodMinPrice = prodMinPriceMap.get(product.getId());
|
||||
final StoreProductCategoryAttribute cateAttr = cateAttrMap.get(product.getId());
|
||||
ESProductDTO esProductDTO = new ESProductDTO().setStoreProdId(product.getId().toString()).setProdArtNum(product.getProdArtNum())
|
||||
.setHasVideo(Boolean.FALSE).setProdCateId(product.getProdCateId().toString()).setCreateTime(DateUtils.getTime())
|
||||
.setProdCateName(ObjectUtils.isNotEmpty(cate) ? cate.getName() : "")
|
||||
.setSaleWeight(WEIGHT_DEFAULT_ZERO.toString()).setRecommendWeight(WEIGHT_DEFAULT_ZERO.toString())
|
||||
.setPopularityWeight(WEIGHT_DEFAULT_ZERO.toString())
|
||||
.setMainPicUrl("").setMainPicName("").setMainPicSize(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() : "")
|
||||
.setProdTitle(product.getProdTitle());
|
||||
if (ObjectUtils.isNotEmpty(cateAttr) && StringUtils.isNotBlank(cateAttr.getStyle())) {
|
||||
esProductDTO.setTags(Collections.singletonList(cateAttr.getStyle()));
|
||||
}
|
||||
esProductDTOList.add(esProductDTO);
|
||||
}
|
||||
// 构建批量操作请求
|
||||
List<BulkOperation> 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);
|
||||
}
|
||||
// 执行批量插入
|
||||
try {
|
||||
BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(Constants.ES_IDX_PRODUCT_INFO).operations(bulkOperations));
|
||||
log.info("批量新增到 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList()));
|
||||
// 有哪些没执行成功的,需要发飞书通知
|
||||
List<String> successIdList = response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList());
|
||||
List<String> unExeIdList = storeProdIdList.stream().map(String::valueOf).filter(x -> !successIdList.contains(x)).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(unExeIdList)) {
|
||||
fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", "以下storeProdId未执行成功: " + unExeIdList);
|
||||
} else {
|
||||
fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 成功", "共处理 " + response.items().size() + " 条记录");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("批量新增到 ES 失败", e);
|
||||
fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", e.getMessage());
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化系统颜色
|
||||
|
|
@ -509,8 +576,7 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
/**
|
||||
* 处理档口客户优惠
|
||||
*/
|
||||
private void handleCusDisc(String tyAtrNo, Map<String, Set<String>> tyExistArtNoColorMap,
|
||||
Map<String, Map<String, List<TyCusDiscImportVO>>> tyCusDiscGroupMap,
|
||||
private void handleCusDisc(String tyAtrNo, Map<String, Set<String>> tyExistArtNoColorMap, Map<String, Map<String, List<TyCusDiscImportVO>>> tyCusDiscGroupMap,
|
||||
Map<String, StoreProductColor> buJuProdColorMap, Map<String, StoreCustomer> buJuStoreCusMap,
|
||||
List<StoreCustomerProductDiscount> prodCusDiscList, Long storeId, Long storeProdId) {
|
||||
// TY货号下有哪些颜色存在客户优惠
|
||||
|
|
@ -529,7 +595,7 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
// TODO 该处TY 与 FHB处理不同
|
||||
// TODO 该处TY 与 FHB处理不同
|
||||
// TODO 该处TY 与 FHB处理不同
|
||||
tyCusDiscList.forEach(tyCusDisc -> {
|
||||
tyCusDiscList.stream().filter(x -> x.getDiscount() > 0).forEach(tyCusDisc -> {
|
||||
StoreProductColor buJuProdColor = Optional.ofNullable(buJuProdColorMap.get(tyColor)).orElseThrow(() -> new ServiceException("没有步橘系统对应的颜色!" + tyColor, HttpStatus.ERROR));
|
||||
StoreCustomer storeCus = Optional.ofNullable(buJuStoreCusMap.get(tyCusDisc.getCusName())).orElseThrow(() -> new ServiceException("没有步橘系统对应的客户!" + tyCusDisc.getCusName(), HttpStatus.ERROR));
|
||||
// 将FHB客户优惠 转为步橘系统优惠
|
||||
|
|
@ -543,9 +609,8 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
* 初始化客户列表
|
||||
*
|
||||
* @param initVO 入参
|
||||
* @return List<StoreCustomer>
|
||||
*/
|
||||
private List<StoreCustomer> initStoreCusList(GtAndTYInitVO initVO) {
|
||||
private void initStoreCusList(GtAndTYInitVO initVO) {
|
||||
List<TyCusImportVO> cacheList = ObjectUtils.defaultIfNull(redisCache
|
||||
.getCacheObject(CacheConstants.MIGRATION_TY_CUS_KEY + initVO.getUserId()), new ArrayList<>());
|
||||
if (CollectionUtils.isEmpty(cacheList)) {
|
||||
|
|
@ -557,7 +622,6 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
.map(x -> new StoreCustomer().setStoreId(initVO.getStoreId()).setCusName(x.getCusName()))
|
||||
.collect(Collectors.toList());
|
||||
this.storeCusMapper.insert(storeCusList);
|
||||
return storeCusList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -674,45 +738,4 @@ public class GtAndTyBiz2Controller extends BaseController {
|
|||
prodAttrMap.put(product_id, prodAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取GT匹配的多个货号中的第一个商品
|
||||
*
|
||||
* @param multiSaleSameGoMap
|
||||
* @param gtSaleGroupMap
|
||||
* @param cleanArtNo
|
||||
* @return
|
||||
*/
|
||||
private List<GtProdSkuVO> getGtFirstSku(Map<String, List<String>> multiSaleSameGoMap, Map<String, List<GtProdSkuVO>> gtSaleGroupMap, String cleanArtNo) {
|
||||
// GT匹配的货号
|
||||
List<String> gtMatchArtNoList = multiSaleSameGoMap.get(cleanArtNo);
|
||||
// GT 最短的货号
|
||||
String shortestArtNo = gtMatchArtNoList.stream().min(Comparator.comparingInt(String::length))
|
||||
.orElse(gtMatchArtNoList.get(0));
|
||||
return gtSaleGroupMap.get(shortestArtNo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 提取货号中的核心数字部分
|
||||
* 例如: z1104 -> 1104, z1087高 -> 1087, z1003-1 -> 1003, 922- -> 922, -8072 -> 8072
|
||||
*
|
||||
* @param articleNumber 货号
|
||||
* @return 核心数字部分
|
||||
*/
|
||||
private String extractCoreArticleNumber(String articleNumber) {
|
||||
if (articleNumber == null || articleNumber.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
// 使用正则表达式匹配第一组连续的数字
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\d+");
|
||||
java.util.regex.Matcher matcher = pattern.matcher(articleNumber);
|
||||
// 返回第一组匹配到的数字
|
||||
if (matcher.find()) {
|
||||
return matcher.group();
|
||||
}
|
||||
// 如果没有找到数字,返回空字符串
|
||||
throw new ServiceException("货号格式错误", HttpStatus.ERROR);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.ruoyi.web.controller.xkt.migartion;
|
||||
|
||||
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;
|
||||
|
|
@ -9,7 +12,10 @@ import com.ruoyi.common.core.domain.R;
|
|||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
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.framework.notice.fs.FsNotice;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYCompareDownloadVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYInitVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtCateVO;
|
||||
|
|
@ -19,11 +25,13 @@ import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyCusImportVO;
|
|||
import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdImportVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdStockVO;
|
||||
import com.ruoyi.xkt.domain.*;
|
||||
import com.ruoyi.xkt.dto.es.ESProductDTO;
|
||||
import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdMinPriceDTO;
|
||||
import com.ruoyi.xkt.enums.EProductStatus;
|
||||
import com.ruoyi.xkt.enums.ListingType;
|
||||
import com.ruoyi.xkt.mapper.*;
|
||||
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;
|
||||
|
|
@ -34,23 +42,26 @@ 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.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.ruoyi.common.constant.Constants.WEIGHT_DEFAULT_ZERO;
|
||||
|
||||
/**
|
||||
* Compare 相关
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/rest/v1/gt-ty")
|
||||
public class GtAndTyBizController extends BaseController {
|
||||
|
||||
final IShipMasterService shipMasterService;
|
||||
final RedisCache redisCache;
|
||||
final StoreProductColorMapper prodColorMapper;
|
||||
final StoreProductColorSizeMapper prodColorSizeMapper;
|
||||
|
|
@ -63,34 +74,8 @@ public class GtAndTyBizController extends BaseController {
|
|||
final StoreProductServiceMapper prodSvcMapper;
|
||||
final StoreProductCategoryAttributeMapper prodCateAttrMapper;
|
||||
final SysProductCategoryMapper prodCateMapper;
|
||||
|
||||
|
||||
// TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍
|
||||
// TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍
|
||||
// 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 上传到图搜服务器之后还要确认
|
||||
|
||||
}
|
||||
final EsClientWrapper esClientWrapper;
|
||||
final FsNotice fsNotice;
|
||||
|
||||
/**
|
||||
* step1
|
||||
|
|
@ -485,8 +470,6 @@ public class GtAndTyBizController extends BaseController {
|
|||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
// 档口客户优惠
|
||||
this.storeCusProdDiscMapper.insert(prodCusDiscList);
|
||||
|
|
@ -495,6 +478,88 @@ public class GtAndTyBizController extends BaseController {
|
|||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* step5
|
||||
*/
|
||||
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
|
||||
@PostMapping("/sync-es/{storeId}")
|
||||
public R<Integer> syncToEs(@PathVariable("storeId") Long storeId) {
|
||||
// 将公共的商品同步到ES
|
||||
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
|
||||
.eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, storeId));
|
||||
if (CollectionUtils.isEmpty(storeProdList)) {
|
||||
return R.fail();
|
||||
}
|
||||
final List<String> storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList());
|
||||
// 所有的分类
|
||||
List<SysProductCategory> prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper<SysProductCategory>()
|
||||
.eq(SysProductCategory::getDelFlag, Constants.UNDELETED));
|
||||
Map<Long, SysProductCategory> prodCateMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getId, x -> x));
|
||||
// 获取当前商品最低价格
|
||||
Map<Long, BigDecimal> prodMinPriceMap = this.prodColorSizeMapper.selectStoreProdMinPriceList(storeProdIdList).stream().collect(Collectors
|
||||
.toMap(StoreProdMinPriceDTO::getStoreProdId, StoreProdMinPriceDTO::getPrice));
|
||||
// 档口商品的属性map
|
||||
Map<Long, StoreProductCategoryAttribute> cateAttrMap = this.prodCateAttrMapper.selectList(new LambdaQueryWrapper<StoreProductCategoryAttribute>()
|
||||
.eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).in(StoreProductCategoryAttribute::getStoreProdId, storeProdIdList))
|
||||
.stream().collect(Collectors.toMap(StoreProductCategoryAttribute::getStoreProdId, x -> x));
|
||||
// 档口商品对应的档口
|
||||
Map<Long, Store> storeMap = this.storeMapper.selectList(new LambdaQueryWrapper<Store>().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<ESProductDTO> 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 BigDecimal prodMinPrice = prodMinPriceMap.get(product.getId());
|
||||
final StoreProductCategoryAttribute cateAttr = cateAttrMap.get(product.getId());
|
||||
ESProductDTO esProductDTO = new ESProductDTO().setStoreProdId(product.getId().toString()).setProdArtNum(product.getProdArtNum())
|
||||
.setHasVideo(Boolean.FALSE).setProdCateId(product.getProdCateId().toString()).setCreateTime(DateUtils.getTime())
|
||||
.setProdCateName(ObjectUtils.isNotEmpty(cate) ? cate.getName() : "")
|
||||
.setSaleWeight(WEIGHT_DEFAULT_ZERO.toString()).setRecommendWeight(WEIGHT_DEFAULT_ZERO.toString())
|
||||
.setPopularityWeight(WEIGHT_DEFAULT_ZERO.toString())
|
||||
.setMainPicUrl("").setMainPicName("").setMainPicSize(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() : "")
|
||||
.setProdTitle(product.getProdTitle());
|
||||
if (ObjectUtils.isNotEmpty(cateAttr) && StringUtils.isNotBlank(cateAttr.getStyle())) {
|
||||
esProductDTO.setTags(Collections.singletonList(cateAttr.getStyle()));
|
||||
}
|
||||
esProductDTOList.add(esProductDTO);
|
||||
}
|
||||
// 构建批量操作请求
|
||||
List<BulkOperation> 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);
|
||||
}
|
||||
// 执行批量插入
|
||||
try {
|
||||
BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(Constants.ES_IDX_PRODUCT_INFO).operations(bulkOperations));
|
||||
log.info("批量新增到 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList()));
|
||||
// 有哪些没执行成功的,需要发飞书通知
|
||||
List<String> successIdList = response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList());
|
||||
List<String> unExeIdList = storeProdIdList.stream().map(String::valueOf).filter(x -> !successIdList.contains(x)).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(unExeIdList)) {
|
||||
fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", "以下storeProdId未执行成功: " + unExeIdList);
|
||||
} else {
|
||||
fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 成功", "共处理 " + response.items().size() + " 条记录");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("批量新增到 ES 失败", e);
|
||||
fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", e.getMessage());
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化系统颜色
|
||||
|
|
@ -573,7 +638,7 @@ public class GtAndTyBizController extends BaseController {
|
|||
// TODO 该处TY 与 FHB处理不同
|
||||
// TODO 该处TY 与 FHB处理不同
|
||||
// TODO 该处TY 与 FHB处理不同
|
||||
tyCusDiscList.forEach(tyCusDisc -> {
|
||||
tyCusDiscList.stream().filter(x -> x.getDiscount() > 0).forEach(tyCusDisc -> {
|
||||
StoreProductColor buJuProdColor = Optional.ofNullable(buJuProdColorMap.get(tyColor)).orElseThrow(() -> new ServiceException("没有步橘系统对应的颜色!" + tyColor, HttpStatus.ERROR));
|
||||
StoreCustomer storeCus = Optional.ofNullable(buJuStoreCusMap.get(tyCusDisc.getCusName())).orElseThrow(() -> new ServiceException("没有步橘系统对应的客户!" + tyCusDisc.getCusName(), HttpStatus.ERROR));
|
||||
// 将FHB客户优惠 转为步橘系统优惠
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtCateVO;
|
|||
import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtProdSkuVO;
|
||||
import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtProdVO;
|
||||
import com.ruoyi.xkt.mapper.SysProductCategoryMapper;
|
||||
import com.ruoyi.xkt.service.shipMaster.IShipMasterService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
|
|
@ -21,10 +20,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
|||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -37,7 +34,6 @@ import java.util.stream.Collectors;
|
|||
@RequestMapping("/rest/v1/gt")
|
||||
public class GtController extends BaseController {
|
||||
|
||||
final IShipMasterService shipMasterService;
|
||||
final RedisCache redisCache;
|
||||
final SysProductCategoryMapper prodCateMapper;
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ public class TyController extends BaseController {
|
|||
*/
|
||||
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
|
||||
@GetMapping("/error/cus/disc/{userId}")
|
||||
public R<CusDiscErrorVO> getErrorCusDisc(@PathVariable Integer userId){
|
||||
public R<CusDiscErrorVO> getErrorCusDisc(@PathVariable Integer userId) {
|
||||
List<TyCusDiscImportVO> cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_DISCOUNT_KEY + userId);
|
||||
List<String> errDiscList = new ArrayList<>();
|
||||
// 1. 有哪些是优惠价大于销售价的
|
||||
|
|
@ -226,11 +226,7 @@ public class TyController extends BaseController {
|
|||
if (cusDiscMap.containsKey(cusName)) {
|
||||
throw new ServiceException(cusName + " : 客户已导入过优惠数据", HttpStatus.ERROR);
|
||||
}
|
||||
|
||||
// TODO 临时去掉
|
||||
// TODO 临时去掉
|
||||
|
||||
/* // 判断货号 + 颜色是否存在,“图识”可能不准
|
||||
// 判断货号 + 颜色是否存在,“图识”可能不准
|
||||
List<TyProdImportVO> tyProdVOList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + userId);
|
||||
// key prod+colorName
|
||||
Map<String, TyProdImportVO> tyProdColorMap = tyProdVOList.stream().collect(Collectors.toMap(x -> x.getProdArtNum() + ":" + x.getColorName(), x -> x));
|
||||
|
|
@ -243,11 +239,7 @@ public class TyController extends BaseController {
|
|||
});
|
||||
if (CollectionUtils.isNotEmpty(errorList)) {
|
||||
throw new ServiceException(errorList.toString(), HttpStatus.ERROR);
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
package com.ruoyi.xkt.service.shipMaster;
|
||||
|
||||
/**
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface IShipMasterService {
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package com.ruoyi.xkt.service.shipMaster.impl;
|
||||
|
||||
import com.ruoyi.xkt.service.shipMaster.IShipMasterService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 公告
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ShipMasterServiceImpl implements IShipMasterService {
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue