diff --git a/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV2.cs b/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV2.cs
index 63d3139..67a57e9 100644
--- a/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV2.cs
+++ b/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV2.cs
@@ -14,6 +14,9 @@ namespace TemuKJD.BLL.ImportConverters
{
///
/// 微信小商店(新版商品详情接口)转拼多多数据源
+ /// 对应示例:title / subTitle / headImg / category / param / brandId /
+ /// skuIdList / skuList.skuInfo / detail.detailImg / expressInfo 等字段
+ /// 与 V1(out_product_id / skus / cats_v2 / head_imgs / attrs / extra_service 等下划线字段)格式不同
///
internal class ConverterWXToPddV2 : GoodsConverterBase
{
@@ -22,10 +25,7 @@ namespace TemuKJD.BLL.ImportConverters
public override string ConverterName => "微信转拼多多数据源V2";
public override PlatformType Platform => PlatformType.WX;
- protected override void ReadContent(string filePath)
- {
- base.ReadContent(filePath);
- }
+
protected override bool IsMatchProvider()
{
@@ -247,12 +247,12 @@ namespace TemuKJD.BLL.ImportConverters
}
///
- /// 从单个SKU节点中提取规格键值对(部分商品SKU不含规格属性,此时返回空列表)
- /// 兼容多种可能出现的字段名
+ /// 从单个SKU节点中提取规格键值对(兼容极少数直接把属性挂在sku节点上的情况)
+ /// 正常情况下规格信息在顶层的 productSaleAttrs 中,见 BuildSkuIdToAttrsMap
///
- private Dictionary GetSkuAttrPairs(JToken sku)
+ private List> GetSkuAttrPairs(JToken sku)
{
- var result = new Dictionary();
+ var result = new List>();
JArray attrArray = sku["skuAttrs"] as JArray
?? sku["attrs"] as JArray
@@ -269,14 +269,96 @@ namespace TemuKJD.BLL.ImportConverters
var value = attr["attrValue"]?.Value() ?? attr["value"]?.Value();
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
- result.Add(key, value);
+ result.Add(new KeyValuePair(key, value));
}
return result;
}
///
- /// 获取SKU(skuList.skuInfo)
+ /// 从顶层 productSaleAttrs 构建 skuId -> [(规格名,规格值)] 的映射
+ /// productSaleAttrs 结构:[{ "key":"型号", "items":[{ "value":"xxx", "imgUrl":"xxx", "skuIds":["xxx"] }] }]
+ ///
+ private Dictionary>> BuildSkuIdToAttrsMap(JObject jsonData)
+ {
+ var map = new Dictionary>>();
+ var saleAttrs = jsonData["productSaleAttrs"] as JArray;
+ if (saleAttrs == null)
+ return map;
+
+ foreach (var attr in saleAttrs)
+ {
+ var key = attr["key"]?.Value();
+ var items = attr["items"] as JArray;
+ if (string.IsNullOrEmpty(key) || items == null)
+ continue;
+
+ foreach (var item in items)
+ {
+ var value = item["value"]?.Value();
+ var skuIds = item["skuIds"] as JArray;
+ if (string.IsNullOrEmpty(value) || skuIds == null)
+ continue;
+
+ foreach (var skuIdToken in skuIds)
+ {
+ var skuId = skuIdToken?.Value();
+ if (string.IsNullOrEmpty(skuId))
+ continue;
+
+ if (!map.TryGetValue(skuId, out var list))
+ {
+ list = new List>();
+ map[skuId] = list;
+ }
+ list.Add(new KeyValuePair(key, value));
+ }
+ }
+ }
+
+ return map;
+ }
+
+ ///
+ /// 从顶层 productSaleAttrs 构建 skuId -> 规格图片(imgUrl) 的映射
+ ///
+ private Dictionary BuildSkuIdToSpecImageMap(JObject jsonData)
+ {
+ var map = new Dictionary();
+ var saleAttrs = jsonData["productSaleAttrs"] as JArray;
+ if (saleAttrs == null)
+ return map;
+
+ foreach (var attr in saleAttrs)
+ {
+ var items = attr["items"] as JArray;
+ if (items == null)
+ continue;
+
+ foreach (var item in items)
+ {
+ var imgUrl = item["imgUrl"]?.Value();
+ var skuIds = item["skuIds"] as JArray;
+ if (string.IsNullOrEmpty(imgUrl) || skuIds == null)
+ continue;
+
+ foreach (var skuIdToken in skuIds)
+ {
+ var skuId = skuIdToken?.Value();
+ if (string.IsNullOrEmpty(skuId))
+ continue;
+
+ if (!map.ContainsKey(skuId))
+ map[skuId] = imgUrl;
+ }
+ }
+ }
+
+ return map;
+ }
+
+ ///
+ /// 获取SKU(skuList.skuInfo),规格信息优先取自顶层 productSaleAttrs
///
private List GetSkusFromNewFormat(JObject jsonData)
{
@@ -286,9 +368,20 @@ namespace TemuKJD.BLL.ImportConverters
if (skus == null)
return result;
+ var skuIdToAttrsMap = BuildSkuIdToAttrsMap(jsonData);
+ var skuIdToSpecImageMap = BuildSkuIdToSpecImageMap(jsonData);
+
foreach (var sku in skus)
{
- var attrPairs = GetSkuAttrPairs(sku);
+ var skuId = sku["skuId"]?.Value() ?? "";
+
+ // 优先使用 productSaleAttrs 中按 skuId 匹配到的规格,取不到时兼容旧字段
+ List> attrPairs;
+ if (!string.IsNullOrEmpty(skuId) && skuIdToAttrsMap.TryGetValue(skuId, out var mappedPairs))
+ attrPairs = mappedPairs;
+ else
+ attrPairs = GetSkuAttrPairs(sku);
+
var specValues = attrPairs.Select(a => $"{a.Key}:{a.Value}").ToList();
// price 单位为分,需要转换为元
@@ -297,14 +390,21 @@ namespace TemuKJD.BLL.ImportConverters
var originPriceInCents = sku["originPrice"]?.Value() ?? priceInCents;
+ string specImage = null;
+ if (!string.IsNullOrEmpty(skuId))
+ skuIdToSpecImageMap.TryGetValue(skuId, out specImage);
+
result.Add(new SkuItem
{
- SkuId = sku["skuId"]?.Value() ?? "",
+ SkuId = skuId,
Spec = string.Join(";", specValues),
Price = priceInYuan,
OriginalPrice = originPriceInCents.ToString(), // 保留原始价格(分)
Stock = sku["stockNum"]?.Value() ?? 999, // 无库存字段时使用默认值
- SpecImage = sku["thumbImg"]?.Value() ?? sku["skuImg"]?.Value() ?? ""
+ SpecImage = specImage
+ ?? sku["thumbImg"]?.Value()
+ ?? sku["skuImg"]?.Value()
+ ?? ""
});
}
@@ -312,13 +412,49 @@ namespace TemuKJD.BLL.ImportConverters
}
///
- /// 获取规格(从skuList.skuInfo中的规格属性汇总去重,若商品无规格属性则返回空列表)
+ /// 获取规格:优先从顶层 productSaleAttrs 汇总(key为规格名,items[].value为规格值),
+ /// 若不存在该字段则退回从每个SKU自身属性字段中提取(兼容旧/异形数据)
///
private List GetSpecsFromNewFormat(JObject jsonData)
{
var result = new List();
- var skus = jsonData.SelectToken("$.skuList.skuInfo") as JArray;
+ var saleAttrs = jsonData["productSaleAttrs"] as JArray;
+ if (saleAttrs != null && saleAttrs.Count > 0)
+ {
+ foreach (var attr in saleAttrs)
+ {
+ var key = attr["key"]?.Value();
+ var items = attr["items"] as JArray;
+ if (string.IsNullOrEmpty(key) || items == null)
+ continue;
+
+ foreach (var item in items)
+ {
+ var value = item["value"]?.Value();
+ if (string.IsNullOrEmpty(value))
+ continue;
+
+ // 去重
+ if (result.Any(x => x.SpecKey == key && x.SpecValue == value))
+ continue;
+
+ result.Add(new SpecItem
+ {
+ SpecKey = key,
+ SpecValue = value,
+ SpecKeyId = 0, // 该格式中没有ID
+ SpecValueId = 0
+ });
+ }
+ }
+
+ if (result.Count > 0)
+ return result;
+ }
+
+ // 兼容处理:没有 productSaleAttrs 时,尝试从每个SKU自身属性字段中提取
+ var skus = jsonData.SelectToken("$.skuList.skuInfo") as JArray;
if (skus == null)
return result;
@@ -326,17 +462,19 @@ namespace TemuKJD.BLL.ImportConverters
{
var attrPairs = GetSkuAttrPairs(sku);
- foreach (var item in attrPairs)
+ foreach (var pair in attrPairs)
{
- // 去重
- if (result.Any(x => x.SpecKey == item.Key && x.SpecValue == item.Value))
+ var key = pair.Key;
+ var value = pair.Value;
+
+ if (result.Any(x => x.SpecKey == key && x.SpecValue == value))
continue;
result.Add(new SpecItem
{
- SpecKey = item.Key,
- SpecValue = item.Value,
- SpecKeyId = 0, // 该格式中没有ID
+ SpecKey = key,
+ SpecValue = value,
+ SpecKeyId = 0,
SpecValueId = 0
});
}