记得上下班打卡 | git大法好,push需谨慎

Commit b85888dc authored by 姜秀龙's avatar 姜秀龙

Merge branch 'refs/heads/dev-1.6-shouqianba' into container-test

parents 38b1182c ee44a556
......@@ -9,16 +9,25 @@ import java.math.BigDecimal;
@Data
public class GoblinAdminSqbGoodsVo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "商品spuId")
private String spuId;
@ApiModelProperty(value = "商品skuId")
private String skuId;
@ApiModelProperty(value = "商品(SPU)名称,用于按商品名搜索与展示")
private String spuTitle;
@ApiModelProperty(value = "规格(SKU)名称")
private String skuTitle;
@ApiModelProperty(value = "单品默认图片的url")
private String skuPic;
@ApiModelProperty(value = "商品描述")
private String productIntroduction;
@ApiModelProperty(value = "商品标题")
@ApiModelProperty(value = "列表展示用:一般为 spuTitle-skuTitle")
private String title;
@ApiModelProperty(value = "单品现价")
......
......@@ -41,13 +41,13 @@ public class SqbPerformanceGoodsController extends BaseController {
}
/**
* 搜索可选商品(skuType=33 的收钱吧商品)
* 搜索可选商品(skuType=33);有关键词时按 SPU 商品名称(goblin_goods.name)模糊匹配,返回展示为「商品名-规格名」
*/
@GetMapping("search")
@ResponseBody
@ApiOperation("搜索收钱吧候选商品")
@ApiOperation("搜索收钱吧候选商品(按商品名称;展示 spu-sku)")
@ApiImplicitParams({
@ApiImplicitParam(type = "query", dataType = "String", name = "keyword", value = "关键词", required = false),
@ApiImplicitParam(type = "query", dataType = "String", name = "keyword", value = "商品名称关键词(匹配 SPU 名称)", required = false),
})
public AjaxResult searchGoods(@RequestParam(value = "keyword", required = false) String keyword) {
ResponseDto<List<GoblinAdminSqbGoodsVo>> resp = sqbPerformanceGoodsService.searchGoods(keyword);
......
......@@ -10,7 +10,8 @@
.section-title { font-weight: bold; margin: 16px 0 8px; }
.auto-offline-bar { margin-bottom: 10px; font-size: 13px; }
.settlement-input { width: 100px; }
.img-thumb { width: 40px; height: 40px; object-fit: cover; border-radius: 4px; }
.img-thumb { width: 40px; height: 40px; object-fit: cover; border-radius: 4px; cursor: pointer; }
.img-thumb:hover { opacity: 0.85; }
.select2-container { min-width: 380px; }
.add-row { margin-bottom: 16px; display: flex; align-items: center; gap: 10px; }
</style>
......@@ -76,9 +77,38 @@
// 内存中维护已关联商品列表
var linkedGoods = [];
/** 与后台一致:商品名-规格名,缺一则只显示有值的一侧 */
function formatSqbSpuSkuLabel(spuName, skuName) {
var s = (spuName || '').trim();
var k = (skuName || '').trim();
if (s && k) {
return s + '-' + k;
}
return s || k || '-';
}
/** 点击缩略图用 layer 预览(与志愿者编辑等页一致) */
function previewCoverImage(src) {
if (!src) {
return;
}
var imgUrl = src;
if (src.indexOf('x-oss-process') !== -1) {
imgUrl = src.split('?')[0];
}
layer.photos({
photos: { data: [{ alt: '商品头图', src: imgUrl }] },
closeBtn: 1,
anim: 5
});
}
$(function () {
initSelect2();
loadLinkedGoods();
$('#linkedGoodsBody').on('click', 'img.img-thumb', function () {
previewCoverImage($(this).attr('src'));
});
});
// 初始化 Select2(AJAX 搜索)
......@@ -96,7 +126,10 @@
processResults: function (resp) {
var list = (resp && resp.data) ? resp.data : [];
return { results: list.map(function (item) {
return { id: item.skuId, text: (item.title || item.spuName || item.skuName), _raw: item };
var spu = item.spuTitle != null ? item.spuTitle : item.spuName;
var sku = item.skuTitle != null ? item.skuTitle : item.skuName;
var text = item.title || formatSqbSpuSkuLabel(spu, sku);
return { id: item.skuId, text: text, _raw: item };
})};
}
}
......@@ -123,7 +156,7 @@
linkedGoods = list.map(function (item) {
return {
skuId: item.skuId, spuId: item.spuId,
spuName: item.spuName || item.skuName, skuName: item.skuName,
spuName: item.spuName || '', skuName: item.skuName || '',
coverPic: item.coverPic || '', price: item.price, stock: item.stock,
settlementPrice: (item.settlementPrice != null ? item.settlementPrice : ''),
persisted: true
......@@ -146,12 +179,12 @@
var priceYuan = (item.price != null && item.price !== '') ? Number(item.price).toFixed(2) : '-';
var settlementVal = item.settlementPrice || '';
var imgHtml = item.coverPic
? '<img src="' + item.coverPic + '" class="img-thumb"/>'
? '<img src="' + item.coverPic + '" class="img-thumb" title="点击放大" alt="商品头图"/>'
: '<span style="color:#ccc;font-size:12px;">无图</span>';
html += '<tr data-idx="' + idx + '">';
html += '<td><small>' + item.skuId + '</small></td>';
html += '<td>' + imgHtml + '</td>';
html += '<td>' + (item.spuName || item.skuName || '-') + '</td>';
html += '<td>' + formatSqbSpuSkuLabel(item.spuName, item.skuName) + '</td>';
html += '<td>' + priceYuan + '</td>';
html += '<td><input type="number" class="form-control settlement-input" value="' + settlementVal
+ '" placeholder="不填按售价" onchange="updateSettlement(' + idx + ', this.value)" min="0" step="0.01"/></td>';
......@@ -171,8 +204,8 @@
}
linkedGoods.push({
skuId: item.skuId, spuId: item.spuId || '',
spuName: item.title || item.spuName || item.skuName,
skuName: item.title || item.skuName || item.spuName,
spuName: (item.spuTitle != null ? item.spuTitle : item.spuName) || '',
skuName: (item.skuTitle != null ? item.skuTitle : item.skuName) || '',
coverPic: item.skuPic || item.coverPic || '',
price: item.price,
stock: (item.skuStock != null ? item.skuStock : item.stock),
......
......@@ -41,10 +41,10 @@ public interface ISqbPerformanceGoodsService {
ResponseDto<GoblinSqbPerfListRespVo> list(String performancesId);
/**
* 搜索收钱吧商品(skuType=33,供关联候选)
* 搜索收钱吧商品(skuType=33);有关键词时按 SPU 商品名称模糊匹配;无关键词时返回少量候选 SKU。
*
* @param keyword 商品名称关键词
* @return 商品列表
* @param keyword 商品(SPU)名称关键词,可为空
* @return 列表项含 spuTitle、skuTitle、title(一般为「商品名-规格名」)
*/
ResponseDto<List<GoblinAdminSqbGoodsVo>> searchGoods(String keyword);
}
......@@ -9,6 +9,7 @@ import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.GoblinAdminSqbGoodsVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfLinkedGoodsVo;
import com.liquidnet.service.goblin.dto.vo.GoblinSqbPerfListRespVo;
import com.liquidnet.service.goblin.entity.GoblinGoods;
import com.liquidnet.service.goblin.entity.GoblinGoodsSku;
import com.liquidnet.service.goblin.entity.GoblinSqbPerformanceConfig;
import com.liquidnet.service.goblin.entity.GoblinSqbPerformanceGoods;
......@@ -24,6 +25,7 @@ import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
......@@ -40,6 +42,26 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
/** skuType=33 代表收钱吧商品 */
private static final int SQB_SKU_TYPE = 33;
private static String sqbSpuSkuDisplay(String spuTitle, String skuTitle) {
String s = spuTitle != null ? spuTitle.trim() : "";
String k = skuTitle != null ? skuTitle.trim() : "";
if (!s.isEmpty() && !k.isEmpty()) {
return s + "-" + k;
}
if (!s.isEmpty()) {
return s;
}
return k;
}
/** 头图:SKU 无图时回落到 SPU 封面(收钱吧 SKU 常未维护 sku_pic) */
private static String pickSkuOrSpuCover(String skuPic, String spuCoverPic) {
if (StringUtils.hasText(skuPic)) {
return skuPic;
}
return StringUtils.hasText(spuCoverPic) ? spuCoverPic : "";
}
@Autowired
private GoblinSqbPerformanceGoodsMapper performanceGoodsMapper;
......@@ -200,6 +222,25 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
Map<String, GoblinGoodsSku> skuMap = goblinGoodsSkuMapper.selectList(skuQuery)
.stream().collect(Collectors.toMap(GoblinGoodsSku::getSkuId, Function.identity(), (a, b) -> a));
List<String> spuIdList = relations.stream()
.map(GoblinSqbPerformanceGoods::getSpuId)
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
Map<String, String> spuNameById = new HashMap<>();
Map<String, String> spuCoverById = new HashMap<>();
if (!spuIdList.isEmpty()) {
LambdaQueryWrapper<GoblinGoods> goodsQuery = new LambdaQueryWrapper<>();
goodsQuery.in(GoblinGoods::getSpuId, spuIdList)
.select(GoblinGoods::getSpuId, GoblinGoods::getName, GoblinGoods::getCoverPic);
for (GoblinGoods g : goblinGoodsMapper.selectList(goodsQuery)) {
if (g.getSpuId() != null) {
spuNameById.put(g.getSpuId(), g.getName());
spuCoverById.put(g.getSpuId(), g.getCoverPic());
}
}
}
List<GoblinSqbPerfLinkedGoodsVo> goodsList = new ArrayList<>();
for (GoblinSqbPerformanceGoods rel : relations) {
GoblinSqbPerfLinkedGoodsVo vo = new GoblinSqbPerfLinkedGoodsVo();
......@@ -212,8 +253,8 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
GoblinGoodsSku sku = skuMap.get(rel.getSkuId());
if (sku != null) {
vo.setSkuName(sku.getName());
vo.setSpuName(sku.getName());
vo.setCoverPic(sku.getSkuPic());
vo.setSpuName(spuNameById.getOrDefault(rel.getSpuId(), ""));
vo.setCoverPic(pickSkuOrSpuCover(sku.getSkuPic(), spuCoverById.get(rel.getSpuId())));
vo.setPrice(sku.getPrice());
vo.setStock(sku.getSkuStock());
}
......@@ -231,11 +272,23 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
@Override
public ResponseDto<List<GoblinAdminSqbGoodsVo>> searchGoods(String keyword) {
try {
// 收钱吧商品的所有核心展示信息均已同步到 SKU(Type=33)表中,直接一次查询避免二次查 SPU
LambdaQueryWrapper<GoblinGoodsSku> skuQuery = new LambdaQueryWrapper<>();
skuQuery.eq(GoblinGoodsSku::getSkuType, SQB_SKU_TYPE);
if (StringUtils.hasText(keyword)) {
skuQuery.like(GoblinGoodsSku::getName, keyword);
LambdaQueryWrapper<GoblinGoods> goodsQuery = new LambdaQueryWrapper<>();
goodsQuery.select(GoblinGoods::getSpuId)
.ne(GoblinGoods::getDelFlg, "1")
.like(GoblinGoods::getName, keyword)
.last("LIMIT 300");
List<String> spuIds = goblinGoodsMapper.selectList(goodsQuery).stream()
.map(GoblinGoods::getSpuId)
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
if (spuIds.isEmpty()) {
return ResponseDto.success(new ArrayList<>());
}
skuQuery.in(GoblinGoodsSku::getSpuId, spuIds);
}
skuQuery.last("LIMIT 50");
List<GoblinGoodsSku> skuList = goblinGoodsSkuMapper.selectList(skuQuery);
......@@ -244,12 +297,36 @@ public class SqbPerformanceGoodsServiceImpl implements ISqbPerformanceGoodsServi
return ResponseDto.success(new ArrayList<>());
}
List<String> spuIdForTitle = skuList.stream()
.map(GoblinGoodsSku::getSpuId)
.filter(StringUtils::hasText)
.distinct()
.collect(Collectors.toList());
Map<String, String> spuTitleById = new HashMap<>();
Map<String, String> spuCoverById = new HashMap<>();
if (!spuIdForTitle.isEmpty()) {
LambdaQueryWrapper<GoblinGoods> gq = new LambdaQueryWrapper<>();
gq.in(GoblinGoods::getSpuId, spuIdForTitle)
.select(GoblinGoods::getSpuId, GoblinGoods::getName, GoblinGoods::getCoverPic);
for (GoblinGoods g : goblinGoodsMapper.selectList(gq)) {
if (g.getSpuId() != null) {
spuTitleById.put(g.getSpuId(), g.getName());
spuCoverById.put(g.getSpuId(), g.getCoverPic());
}
}
}
List<GoblinAdminSqbGoodsVo> result = new ArrayList<>();
for (GoblinGoodsSku sku : skuList) {
GoblinAdminSqbGoodsVo vo = new GoblinAdminSqbGoodsVo();
vo.setSpuId(sku.getSpuId());
vo.setSkuId(sku.getSkuId());
vo.setTitle(sku.getName());
vo.setSkuPic(sku.getSkuPic());
String spuTitle = spuTitleById.getOrDefault(sku.getSpuId(), "");
String skuTitle = sku.getName() != null ? sku.getName() : "";
vo.setSpuTitle(spuTitle);
vo.setSkuTitle(skuTitle);
vo.setTitle(sqbSpuSkuDisplay(spuTitle, skuTitle));
vo.setSkuPic(pickSkuOrSpuCover(sku.getSkuPic(), spuCoverById.get(sku.getSpuId())));
vo.setPrice(sku.getPrice());
vo.setSkuStock(sku.getSkuStock());
result.add(vo);
......
......@@ -17,7 +17,11 @@ import com.liquidnet.service.goblin.dto.GoblinGoodsSpecDto;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtGoodsSqbAddParam;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinMgtCategorySpecVo;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.entity.GoblinGoods;
import com.liquidnet.service.goblin.entity.GoblinGoodsSku;
import com.liquidnet.service.goblin.entity.GoblinSqbGoodsExt;
import com.liquidnet.service.goblin.mapper.GoblinGoodsMapper;
import com.liquidnet.service.goblin.mapper.GoblinGoodsSkuMapper;
import com.liquidnet.service.goblin.mapper.GoblinSqbGoodsExtMapper;
import com.liquidnet.service.goblin.service.manage.IGoblinStoreMgtSqbGoodsService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
......@@ -50,6 +54,10 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
@Autowired
GoblinSqbGoodsExtMapper goblinSqbGoodsExtMapper;
@Autowired
private GoblinGoodsMapper goblinGoodsMapper;
@Autowired
private GoblinGoodsSkuMapper goblinGoodsSkuMapper;
@Autowired
private SqbBiz goblinShouQianBaService;
......@@ -311,6 +319,15 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
GoblinStoreMgtGoodsSqbAddParam initParam = new GoblinStoreMgtGoodsSqbAddParam();
GoblinGoodsInfoVo updateSpuInfoVo = initParam.initEditGoodsInfoVo(mgtGoodsAddParam, mgtGoodsInfoVo);
// Redis 反序列化缺 spuType 时 primitive int 为 0,全量 $set 会误覆盖 Mongo 中的 33 等类型;以 MySQL 为准回填
LambdaQueryWrapper<GoblinGoods> spuTypeQ = new LambdaQueryWrapper<GoblinGoods>()
.eq(GoblinGoods::getSpuId, spuId)
.select(GoblinGoods::getSpuType)
.last("LIMIT 1");
GoblinGoods goodsRow = goblinGoodsMapper.selectOne(spuTypeQ);
if (goodsRow != null && goodsRow.getSpuType() != null) {
updateSpuInfoVo.setSpuType(goodsRow.getSpuType());
}
boolean updateImageFlg = false;
List<String> paramImageList = mgtGoodsAddParam.getConverImages();
......@@ -398,6 +415,19 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
.filter(ext -> StringUtils.isNotBlank(ext.getSqbSkuId()) && StringUtils.isNotBlank(ext.getSkuId()))
.collect(Collectors.toMap(GoblinSqbGoodsExt::getSqbSkuId, GoblinSqbGoodsExt::getSkuId, (a, b) -> a));
List<String> localSkuIdsForType = new ArrayList<>(new LinkedHashSet<>(sqbSkuToLocalSkuMap.values()));
Map<String, Integer> skuTypeByLocalId = new HashMap<>();
if (!localSkuIdsForType.isEmpty()) {
LambdaQueryWrapper<GoblinGoodsSku> typeQ = new LambdaQueryWrapper<GoblinGoodsSku>()
.in(GoblinGoodsSku::getSkuId, localSkuIdsForType)
.select(GoblinGoodsSku::getSkuId, GoblinGoodsSku::getSkuType);
for (GoblinGoodsSku row : goblinGoodsSkuMapper.selectList(typeQ)) {
if (row.getSkuId() != null && row.getSkuType() != null) {
skuTypeByLocalId.put(row.getSkuId(), row.getSkuType());
}
}
}
boolean updated = false;
LinkedList<Object[]> updateGoodsSkuObjs = CollectionUtil.linkedListObjectArr();
for (MallProductsQueryData.Sku sqbSku : skuResults) {
......@@ -413,6 +443,10 @@ public class GoblinStoreMgtSqbGoodsServiceImpl implements IGoblinStoreMgtSqbGood
if (skuInfoVo == null || !"0".equals(skuInfoVo.getDelFlg())) {
continue;
}
Integer persistedSkuType = skuTypeByLocalId.get(localSkuId);
if (persistedSkuType != null) {
skuInfoVo.setSkuType(persistedSkuType);
}
skuInfoVo.setName(sqbSku.getSkuName());
if (sqbSku.getPrice() != null) {
skuInfoVo.setPrice(SqbAmountUtils.fenToYuan(sqbSku.getPrice()));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment