diff --git a/TEMUKJD/BLL/ImportConverters/ConvertToPddFactory.cs b/TEMUKJD/BLL/ImportConverters/ConvertToPddFactory.cs
index 25dc756..ce208b0 100644
--- a/TEMUKJD/BLL/ImportConverters/ConvertToPddFactory.cs
+++ b/TEMUKJD/BLL/ImportConverters/ConvertToPddFactory.cs
@@ -17,6 +17,8 @@ namespace TemuKJD.BLL.ImportConverts
new ConverterWXToPddV1(),
new ConverterWXToPddV2(),
new ConverterWXToPddV3(),
+ new ConverterWXToPddV4(),
+ new ConverterWXToPddV5(),
};
public static PDDFrontProductInfo5 Convert(string filePath)
{
diff --git a/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV4.cs b/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV4.cs
new file mode 100644
index 0000000..b5a6223
--- /dev/null
+++ b/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV4.cs
@@ -0,0 +1,454 @@
+using AllBase.Model.Result;
+using AllBase.Model.Result.PDDResult;
+using NaiBa.Util.Extension;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace TemuKJD.BLL.ImportConverters
+{
+ ///
+ /// 微信转拼多多数据源 V4版本
+ /// 针对微信商品详情API(/channels/ec/product/get)返回的完整数据结构
+ ///
+ /// 数据结构特点:
+ /// - 顶层为 { detail: { product: { product_key, info, product_skus, ... } } }
+ /// - info 节点包含商品基本信息、主图、详情图、参数、SKU列表等
+ /// - product_skus 节点包含完整的SKU信息(含库存、价格、规格)
+ /// - product_sale_attrs 节点包含销售属性(颜色、尺码)
+ /// - extra_service 节点包含售后服务信息
+ /// - qualification_list 节点包含资质信息
+ ///
+ internal class ConverterWXToPddV4 : GoodsConverterBase
+ {
+ private JObject _jsonRoot;
+ private JObject _productNode; // detail.product
+ private JObject _infoNode; // detail.product.info
+ private JArray _skuList; // detail.product.info.product_skus
+ private JArray _saleAttrs; // detail.product.info.product_sale_attrs
+
+ public override string ConverterName => "微信转拼多多数据源 V4";
+
+ public override PlatformType Platform => PlatformType.WX;
+
+ protected override bool IsMatchProvider()
+ {
+ try
+ {
+ _jsonRoot = JsonConvert.DeserializeObject(RawData);
+ if (_jsonRoot == null) return false;
+
+ // 1. 检查是否为详情API格式(detail.product 结构)
+ var detail = _jsonRoot.SelectToken("$.detail") as JObject;
+ if (detail == null) return false;
+
+ var product = detail.SelectToken("$.product") as JObject;
+ if (product == null) return false;
+
+ // 2. 检查 product_key 是否存在
+ var productKey = product.SelectToken("$.product_key") as JObject;
+ if (productKey == null) return false;
+
+ var productId = productKey.SelectToken("$.product_id")?.ToString();
+ if (string.IsNullOrEmpty(productId)) return false;
+
+ // 3. 检查 info 节点是否存在
+ var info = product.SelectToken("$.info") as JObject;
+ if (info == null) return false;
+
+ // 4. 检查是否有标题
+ var title = info.SelectToken("$.title")?.ToString();
+ if (string.IsNullOrEmpty(title)) return false;
+
+ // 5. 检查是否有SKU列表
+ var skus = product.SelectToken("$.product_skus") as JArray;
+ if (skus == null || skus.Count == 0) return false;
+
+ // 缓存节点
+ _productNode = product;
+ _infoNode = info;
+ _skuList = skus;
+ _saleAttrs = info.SelectToken("$.product_sale_attrs") as JArray;
+
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ protected override PDDFrontProductInfo5 ConverterProvider()
+ {
+ var product = new PDDFrontProductInfo5
+ {
+ Platform = Platform,
+ GoodsId = ParseGoodsId()
+ };
+
+ // ========== 1. 商品基本信息 ==========
+ product.Title = GetStringValue(_infoNode, "title");
+ product.Description = GetStringValue(_infoNode, "short_title");
+ if (string.IsNullOrEmpty(product.Description))
+ {
+ product.Description = GetStringValue(_infoNode, "ai_gen_short_title");
+ }
+
+ // ========== 2. 品牌信息 ==========
+ product.BrandId = GetLongValue(_infoNode, "brand_id");
+
+ // ========== 3. 类目信息 ==========
+ product.CategoryId = GetCategoryId();
+ product.CategoryPath = GetCategoryPath();
+
+ // ========== 4. 主图 ==========
+ product.MainImages = GetMainImages();
+
+ // ========== 5. 详情图 ==========
+ product.DetailImages = GetDetailImages();
+
+ // ========== 6. 商品属性 ==========
+ product.Propertys = GetProperties();
+
+ // ========== 7. SKU和规格信息 ==========
+ var skuResult = GetSkusAndSpecs();
+ product.Skus = skuResult.Item1;
+ product.Specs = skuResult.Item2;
+
+ // ========== 8. 其他信息 ==========
+ product.ThumbUrl = product.MainImages.FirstOrDefault() ?? string.Empty;
+ product.MallId = 0;
+ product.Price = GetMinPrice();
+ product.Videos = GetVideoUrls();
+
+ return product;
+ }
+
+ #region 核心字段解析
+
+ ///
+ /// 解析商品ID
+ ///
+ private long ParseGoodsId()
+ {
+ var productId = _productNode.SelectToken("$.product_key.product_id")?.ToString();
+ if (long.TryParse(productId, out var result))
+ return result;
+
+ // 回退到文件路径
+ return Path.GetFileNameWithoutExtension(FilePath).ParseToLong();
+ }
+
+ ///
+ /// 获取类目ID(取最细分类目)
+ ///
+ private int GetCategoryId()
+ {
+ var category = _infoNode["category"] as JArray;
+ if (category == null || category.Count == 0)
+ return 0;
+
+ // 取最后一个类目(最细分类目)
+ var lastCat = category.Last as JObject;
+ return lastCat?["cat_id"]?.Value() ?? 0;
+ }
+
+ ///
+ /// 获取类目路径
+ ///
+ private List GetCategoryPath()
+ {
+ var result = new List();
+ var category = _infoNode["category"] as JArray;
+ if (category == null)
+ return result;
+
+ foreach (var cat in category)
+ {
+ var catId = cat["cat_id"]?.Value();
+ if (catId.HasValue && catId.Value > 0)
+ result.Add(catId.Value);
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取主图列表
+ ///
+ private List GetMainImages()
+ {
+ var result = new List();
+
+ // 优先使用 head_img 数组
+ var headImg = _infoNode["head_img"] as JArray;
+ if (headImg != null && headImg.Count > 0)
+ {
+ foreach (var img in headImg)
+ {
+ var url = img?.Value();
+ if (!string.IsNullOrEmpty(url))
+ result.Add(url);
+ }
+ return result;
+ }
+
+ // 回退到 head_img_infos
+ var headImgInfos = _infoNode["head_img_infos"] as JArray;
+ if (headImgInfos != null)
+ {
+ foreach (var img in headImgInfos)
+ {
+ var url = img["img_url"]?.Value();
+ if (!string.IsNullOrEmpty(url))
+ result.Add(url);
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取详情图列表
+ ///
+ private List GetDetailImages()
+ {
+ var result = new List();
+ var detail = _infoNode["detail"] as JObject;
+ if (detail == null)
+ return result;
+
+ var detailImg = detail["detail_img"] as JArray;
+ if (detailImg == null)
+ return result;
+
+ foreach (var img in detailImg)
+ {
+ var url = img?.Value();
+ if (!string.IsNullOrEmpty(url))
+ result.Add(url);
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取商品属性列表(从 param 节点解析)
+ ///
+ private List GetProperties()
+ {
+ var result = new List();
+ var param = _infoNode["param"] as JArray;
+ if (param == null)
+ return result;
+
+ foreach (var item in param)
+ {
+ var categorys = item["categorys"] as JArray;
+ if (categorys == null || categorys.Count < 2)
+ continue;
+
+ var key = categorys[0]?["name"]?.Value();
+ var value = categorys[1]?["name"]?.Value();
+
+ if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
+ {
+ // 去重
+ if (!result.Any(p => p.Key == key))
+ {
+ result.Add(new Property
+ {
+ Key = key,
+ Value = value
+ });
+ }
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取视频URL列表
+ ///
+ private List GetVideoUrls()
+ {
+ var result = new List();
+ var headVideoInfo = _infoNode["head_video_info"] as JArray;
+ if (headVideoInfo == null)
+ return result;
+
+ foreach (var video in headVideoInfo)
+ {
+ var url = video["video_url"]?.Value();
+ if (!string.IsNullOrEmpty(url))
+ result.Add(url);
+ }
+
+ return result;
+ }
+
+ #endregion
+
+ #region SKU和规格解析
+
+ ///
+ /// 获取SKU和规格信息
+ ///
+ private Tuple, List> GetSkusAndSpecs()
+ {
+ var skuList = new List();
+ var specList = new List();
+
+ if (_skuList == null || _skuList.Count == 0)
+ return new Tuple, List>(skuList, specList);
+
+ // 收集所有规格
+ var specDict = new Dictionary>();
+
+ foreach (var sku in _skuList)
+ {
+ var skuObj = sku as JObject;
+ if (skuObj == null) continue;
+
+ // 获取 SKU 基本信息
+ var skuKey = skuObj["sku_key"] as JObject;
+ var skuInfo = skuObj["product_sku_info"] as JObject;
+ if (skuKey == null || skuInfo == null) continue;
+
+ var skuId = skuKey["sku_id"]?.Value() ?? string.Empty;
+ var outSkuId = skuKey["out_sku_id"]?.Value() ?? string.Empty;
+
+ // 解析销售属性
+ var saleParams = skuInfo["sale_param"] as JArray;
+ var specValues = new List();
+
+ if (saleParams != null)
+ {
+ foreach (var param in saleParams)
+ {
+ var paramV2 = param["param_v2"] as JObject;
+ if (paramV2 == null) continue;
+
+ var attrName = paramV2["attr_name"]?.Value() ?? string.Empty;
+ var attrValue = paramV2["attr_value_name"]?.Value() ?? string.Empty;
+
+ if (!string.IsNullOrEmpty(attrName) && !string.IsNullOrEmpty(attrValue))
+ {
+ specValues.Add($"{attrName}:{attrValue}");
+
+ // 收集规格
+ if (!specDict.ContainsKey(attrName))
+ specDict[attrName] = new HashSet();
+ specDict[attrName].Add(attrValue);
+ }
+ }
+ }
+
+ // 价格(单位:分)
+ var salePrice = skuInfo["sale_price"]?.Value() ?? 0;
+
+ // 库存
+ var stockInfo = skuInfo["stock_info"] as JObject;
+ var stockNum = 0;
+ if (stockInfo != null)
+ {
+ var stockStr = stockInfo["stock_num"]?.Value();
+ if (!string.IsNullOrEmpty(stockStr))
+ {
+ int.TryParse(stockStr, out stockNum);
+ }
+ }
+
+ // 缩略图
+ var thumbImg = skuInfo["thumb_img"]?.Value() ?? string.Empty;
+
+ skuList.Add(new SkuItem
+ {
+ SkuId = !string.IsNullOrEmpty(outSkuId) ? outSkuId : skuId,
+ Spec = string.Join(";", specValues),
+ Price = salePrice / 100, // 分转元
+ OriginalPrice = salePrice.ToString(),
+ Stock = stockNum,
+ SpecImage = thumbImg
+ });
+ }
+
+ // 构建规格列表
+ foreach (var spec in specDict)
+ {
+ foreach (var value in spec.Value)
+ {
+ specList.Add(new SpecItem
+ {
+ SpecKey = spec.Key,
+ SpecValue = value,
+ SpecKeyId = 0,
+ SpecValueId = 0
+ });
+ }
+ }
+
+ return new Tuple, List>(skuList, specList);
+ }
+
+ ///
+ /// 获取最低价格(元)
+ ///
+ private decimal GetMinPrice()
+ {
+ if (_skuList == null || _skuList.Count == 0)
+ return 0;
+
+ var minPrice = decimal.MaxValue;
+
+ foreach (var sku in _skuList)
+ {
+ var skuObj = sku as JObject;
+ if (skuObj == null) continue;
+
+ var skuInfo = skuObj["product_sku_info"] as JObject;
+ if (skuInfo == null) continue;
+
+ var price = skuInfo["sale_price"]?.Value() ?? 0;
+ if (price > 0 && price < minPrice)
+ minPrice = price;
+ }
+
+ // 回退到 sku_list.min_price
+ if (minPrice == decimal.MaxValue)
+ {
+ var skuListInfo = _infoNode["sku_list"] as JObject;
+ var minPriceToken = skuListInfo?["min_price"]?.Value() ?? 0;
+ return minPriceToken / 100;
+ }
+
+ return minPrice > 0 ? minPrice / 100 : 0;
+ }
+
+ #endregion
+
+ #region 辅助方法
+
+ private string GetStringValue(JObject obj, string path)
+ {
+ return obj?.SelectToken(path)?.Value() ?? string.Empty;
+ }
+
+ private long GetLongValue(JObject obj, string path)
+ {
+ var token = obj?.SelectToken(path);
+ if (token == null) return 0;
+
+ if (token.Type == JTokenType.String)
+ return long.TryParse(token.Value(), out var result) ? result : 0;
+
+ return token.Value();
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV5.cs b/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV5.cs
new file mode 100644
index 0000000..7697754
--- /dev/null
+++ b/TEMUKJD/BLL/ImportConverters/ConverterWXToPddV5.cs
@@ -0,0 +1,529 @@
+using AllBase.Model.Result;
+using AllBase.Model.Result.PDDResult;
+using NaiBa.Util.Extension;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace TemuKJD.BLL.ImportConverters
+{
+ ///
+ /// 微信转拼多多数据源 V5版本
+ /// 针对扁平化结构(含 _raw 节点 + 顶层冗余字段)
+ ///
+ /// 数据结构特点:
+ /// - 顶层包含 _raw、_src、appid、brandId、catId 等元信息
+ /// - 核心商品数据在 _raw 节点内(驼峰命名:headImg、skuList、detail等)
+ /// - 顶层同时冗余了部分字段(headImg、headImgs、saleAttrs、skuSpecs等)
+ /// - SKU价格使用 isDiscounted + estimatePrice 计算优惠后价格
+ /// - 类目路径为字符串 "1208/1242/1244" 格式
+ ///
+ internal class ConverterWXToPddV5 : GoodsConverterBase
+ {
+ private JObject _jsonRoot;
+ private JObject _rawNode; // _raw 节点
+ private JArray _skuInfoList; // _raw.skuList.skuInfo
+ private JArray _saleAttrs; // 顶层 saleAttrs 或 _raw.saleAttrs
+ private JArray _skuSpecs; // 顶层 skuSpecs
+
+ public override string ConverterName => "微信转拼多多数据源 V5";
+
+ public override PlatformType Platform => PlatformType.WX;
+
+ protected override bool IsMatchProvider()
+ {
+ try
+ {
+ _jsonRoot = JsonConvert.DeserializeObject(RawData);
+ if (_jsonRoot == null) return false;
+
+ // 1. 检查 _raw 节点是否存在
+ var raw = _jsonRoot.SelectToken("$._raw") as JObject;
+ if (raw == null) return false;
+
+ // 2. 检查标题是否存在
+ var title = raw.SelectToken("$.title")?.ToString();
+ if (string.IsNullOrEmpty(title)) return false;
+
+ // 3. 检查 headImg 是否存在且为数组
+ var headImg = raw.SelectToken("$.headImg") as JArray;
+ if (headImg == null || headImg.Count == 0) return false;
+
+ // 4. 检查 skuList.skuInfo 是否存在且为数组
+ var skuList = raw.SelectToken("$.skuList") as JObject;
+ if (skuList == null) return false;
+
+ var skuInfo = skuList.SelectToken("$.skuInfo") as JArray;
+ if (skuInfo == null || skuInfo.Count == 0) return false;
+
+ // 5. 检查第一个SKU是否有skuId
+ var firstSku = skuInfo.FirstOrDefault() as JObject;
+ if (firstSku == null) return false;
+
+ var skuId = firstSku.SelectToken("$.skuId")?.ToString();
+ if (string.IsNullOrEmpty(skuId)) return false;
+
+ // 缓存节点
+ _rawNode = raw;
+ _skuInfoList = skuInfo;
+ _saleAttrs = _jsonRoot.SelectToken("$.saleAttrs") as JArray
+ ?? raw.SelectToken("$.saleAttrs") as JArray;
+ _skuSpecs = _jsonRoot.SelectToken("$.skuSpecs") as JArray;
+
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ protected override PDDFrontProductInfo5 ConverterProvider()
+ {
+ var product = new PDDFrontProductInfo5
+ {
+ Platform = Platform,
+ GoodsId = ParseGoodsId()
+ };
+
+ // ========== 1. 商品基本信息 ==========
+ product.Title = GetStringValue(_rawNode, "title");
+ product.Description = GetStringValue(_rawNode, "subTitle");
+ if (string.IsNullOrEmpty(product.Description))
+ {
+ product.Description = GetStringValue(_jsonRoot, "subTitle");
+ }
+
+ // ========== 2. 品牌信息 ==========
+ product.BrandId = GetLongValue(_rawNode, "brandId");
+
+ // ========== 3. 类目信息 ==========
+ product.CategoryId = GetCategoryId();
+ product.CategoryPath = GetCategoryPath();
+
+ // ========== 4. 主图 ==========
+ product.MainImages = GetMainImages();
+
+ // ========== 5. 详情图 ==========
+ product.DetailImages = GetDetailImages();
+
+ // ========== 6. 商品属性 ==========
+ product.Propertys = GetProperties();
+
+ // ========== 7. SKU和规格信息 ==========
+ var skuResult = GetSkusAndSpecs();
+ product.Skus = skuResult.Item1;
+ product.Specs = skuResult.Item2;
+
+ // ========== 8. 其他信息 ==========
+ product.ThumbUrl = product.MainImages.FirstOrDefault() ?? string.Empty;
+ product.MallId = 0;
+ product.Price = GetMinPrice();
+ product.Videos = new List();
+
+ return product;
+ }
+
+ #region 核心字段解析
+
+ ///
+ /// 解析商品ID
+ ///
+ private long ParseGoodsId()
+ {
+ // 优先从 productId / itemId 解析
+ var productId = GetStringValue(_jsonRoot, "productId");
+ if (string.IsNullOrEmpty(productId))
+ productId = GetStringValue(_jsonRoot, "itemId");
+
+ if (long.TryParse(productId, out var result))
+ return result;
+
+ // 回退到 expressInfo.productId
+ var expressProductId = _rawNode.SelectToken("$.expressInfo.productId")?.ToString();
+ if (long.TryParse(expressProductId, out var result2))
+ return result2;
+
+ // 最后回退到文件路径
+ return Path.GetFileNameWithoutExtension(FilePath).ParseToLong();
+ }
+
+ ///
+ /// 获取类目ID(从 catId 字符串 "1208/1242/1244" 解析)
+ ///
+ private int GetCategoryId()
+ {
+ // 优先从顶层 catId 解析
+ var catIdStr = GetStringValue(_jsonRoot, "catId");
+ var catId = ParseLastCatId(catIdStr);
+ if (catId > 0) return catId;
+
+ // 回退到 _raw.category 数组
+ var category = _rawNode["category"] as JArray;
+ if (category != null && category.Count > 0)
+ {
+ var lastCat = category.Last as JObject;
+ var lastCatId = lastCat?["catId"]?.Value();
+ if (int.TryParse(lastCatId, out var result))
+ return result;
+ }
+
+ // 回退到 nodeCatId
+ var nodeCatId = GetStringValue(_rawNode, "nodeCatId");
+ if (int.TryParse(nodeCatId, out var nodeResult))
+ return nodeResult;
+
+ return 0;
+ }
+
+ ///
+ /// 获取类目路径
+ ///
+ private List GetCategoryPath()
+ {
+ var result = new List();
+
+ // 优先从 _raw.category 数组解析
+ var category = _rawNode["category"] as JArray;
+ if (category != null && category.Count > 0)
+ {
+ foreach (var cat in category)
+ {
+ var _catIdStr = cat["catId"]?.Value();
+ if (int.TryParse(_catIdStr, out var catId) && catId > 0)
+ result.Add(catId);
+ }
+ if (result.Count > 0) return result;
+ }
+
+ // 回退到顶层 catId 字符串
+ var catIdStr = GetStringValue(_jsonRoot, "catId");
+ if (!string.IsNullOrEmpty(catIdStr))
+ {
+ foreach (var part in catIdStr.Split('/'))
+ {
+ if (int.TryParse(part.Trim(), out var catId) && catId > 0)
+ result.Add(catId);
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// 从 "1208/1242/1244" 解析最后一个类目ID
+ ///
+ private int ParseLastCatId(string catIdStr)
+ {
+ if (string.IsNullOrEmpty(catIdStr))
+ return 0;
+
+ var parts = catIdStr.Split('/');
+ if (parts.Length == 0) return 0;
+
+ var lastPart = parts[parts.Length - 1].Trim();
+ return int.TryParse(lastPart, out var result) ? result : 0;
+ }
+
+ ///
+ /// 获取主图列表
+ ///
+ private List GetMainImages()
+ {
+ var result = new List();
+
+ // 优先从 _raw.headImg 解析
+ var headImg = _rawNode["headImg"] as JArray;
+ if (headImg != null && headImg.Count > 0)
+ {
+ foreach (var img in headImg)
+ {
+ var url = img?.Value();
+ if (!string.IsNullOrEmpty(url))
+ result.Add(url);
+ }
+ return result;
+ }
+
+ // 回退到顶层 headImg / headImgs
+ var topHeadImg = _jsonRoot.SelectToken("$.headImg") as JArray
+ ?? _jsonRoot.SelectToken("$.headImgs") as JArray;
+ if (topHeadImg != null)
+ {
+ foreach (var img in topHeadImg)
+ {
+ var url = img?.Value();
+ if (!string.IsNullOrEmpty(url))
+ result.Add(url);
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取详情图列表
+ ///
+ private List GetDetailImages()
+ {
+ var result = new List();
+
+ // 从 _raw.detail.detailImg 解析
+ var detail = _rawNode["detail"] as JObject;
+ if (detail == null)
+ return result;
+
+ var detailImg = detail["detailImg"] as JArray;
+ if (detailImg == null)
+ return result;
+
+ foreach (var img in detailImg)
+ {
+ var url = img?.Value();
+ if (!string.IsNullOrEmpty(url))
+ result.Add(url);
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取商品属性列表(从 _raw.param 解析)
+ ///
+ private List GetProperties()
+ {
+ var result = new List();
+ var param = _rawNode["param"] as JArray;
+ if (param == null)
+ return result;
+
+ foreach (var item in param)
+ {
+ var categorys = item["categorys"] as JArray;
+ if (categorys == null || categorys.Count < 2)
+ continue;
+
+ var key = categorys[0]?["name"]?.Value();
+ var value = categorys[1]?["name"]?.Value();
+
+ if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
+ {
+ // 去重
+ if (!result.Any(p => p.Key == key))
+ {
+ result.Add(new Property
+ {
+ Key = key,
+ Value = value
+ });
+ }
+ }
+ }
+
+ return result;
+ }
+
+ #endregion
+
+ #region SKU和规格解析
+
+ ///
+ /// 获取SKU和规格信息
+ ///
+ private Tuple ,List> GetSkusAndSpecs()
+ {
+ var skuList = new List();
+ var specList = new List();
+
+ if (_skuInfoList == null || _skuInfoList.Count == 0)
+ return new Tuple, List>(skuList, specList);
+
+ // 构建 skuSpecs 映射(skuId -> spec文本)
+ var skuSpecDict = new Dictionary();
+ if (_skuSpecs != null)
+ {
+ foreach (var spec in _skuSpecs)
+ {
+ var skuId = spec["skuId"]?.Value();
+ var specText = spec["spec"]?.Value();
+ if (!string.IsNullOrEmpty(skuId) && !string.IsNullOrEmpty(specText))
+ {
+ skuSpecDict[skuId] = specText;
+ }
+ }
+ }
+
+ // 收集所有规格
+ var specDict = new Dictionary>();
+
+ foreach (var sku in _skuInfoList)
+ {
+ var skuObj = sku as JObject;
+ if (skuObj == null) continue;
+
+ var skuId = skuObj["skuId"]?.Value() ?? string.Empty;
+ if (string.IsNullOrEmpty(skuId)) continue;
+
+ // 解析规格
+ string specText = string.Empty;
+ var specValues = new List();
+
+ if (skuSpecDict.TryGetValue(skuId, out var cachedSpec))
+ {
+ specText = cachedSpec;
+ // 解析 "颜色分类:牛油果/尺码:S" 格式
+ foreach (var part in cachedSpec.Split('/'))
+ {
+ var kv = part.Split(':');
+ if (kv.Length == 2)
+ {
+ var key = kv[0].Trim();
+ var value = kv[1].Trim();
+ specValues.Add($"{key}:{value}");
+
+ if (!specDict.ContainsKey(key))
+ specDict[key] = new HashSet();
+ specDict[key].Add(value);
+ }
+ }
+ }
+
+ // 价格解析:优先使用 estimatePrice(优惠后),否则用 originPrice
+ var originPrice = skuObj["originPrice"]?.Value() ?? 0;
+ var estimatePrice = skuObj["estimatePrice"]?.Value() ?? 0;
+ var price = skuObj["price"]?.Value() ?? 0;
+
+ // 实际售价:优先 estimatePrice,其次 price,最后 originPrice
+ var actualPrice = estimatePrice > 0 ? estimatePrice
+ : price > 0 ? price
+ : originPrice;
+
+ // 库存:从 spuTotalStock 均分(SKU级别无库存字段)
+ var totalStock = GetTotalStock();
+ var skuCount = _skuInfoList.Count;
+ var stockPerSku = skuCount > 0 ? totalStock / skuCount : 0;
+
+ skuList.Add(new SkuItem
+ {
+ SkuId = skuId,
+ Spec = specText,
+ Price = actualPrice / 100, // 分转元
+ OriginalPrice = originPrice.ToString(),
+ Stock = stockPerSku,
+ SpecImage = string.Empty // 该结构无SKU图片
+ });
+ }
+
+ // 构建规格列表(优先从 saleAttrs 构建)
+ if (_saleAttrs != null && _saleAttrs.Count > 0)
+ {
+ foreach (var attr in _saleAttrs)
+ {
+ var key = attr["key"]?.Value() ?? string.Empty;
+ var values = attr["values"] as JArray;
+ if (values == null) continue;
+
+ foreach (var value in values)
+ {
+ var valueStr = value?.Value() ?? string.Empty;
+ if (!string.IsNullOrEmpty(valueStr))
+ {
+ specList.Add(new SpecItem
+ {
+ SpecKey = key,
+ SpecValue = valueStr,
+ SpecKeyId = 0,
+ SpecValueId = 0
+ });
+ }
+ }
+ }
+ }
+ else
+ {
+ // 回退到从SKU中收集的规格
+ foreach (var spec in specDict)
+ {
+ foreach (var value in spec.Value)
+ {
+ specList.Add(new SpecItem
+ {
+ SpecKey = spec.Key,
+ SpecValue = value,
+ SpecKeyId = 0,
+ SpecValueId = 0
+ });
+ }
+ }
+ }
+
+ return new Tuple, List>(skuList, specList);
+ }
+
+ ///
+ /// 获取总库存
+ ///
+ private int GetTotalStock()
+ {
+ var spuTotalStock = _rawNode["spuTotalStock"] as JObject;
+ if (spuTotalStock == null) return 0;
+
+ var stockNumStr = spuTotalStock["stockNum"]?.Value();
+ if (int.TryParse(stockNumStr, out var result))
+ return result;
+
+ return 0;
+ }
+
+ ///
+ /// 获取最低价格(元)
+ ///
+ private decimal GetMinPrice()
+ {
+ if (_skuInfoList == null || _skuInfoList.Count == 0)
+ return 0;
+
+ var minPrice = decimal.MaxValue;
+
+ foreach (var sku in _skuInfoList)
+ {
+ var skuObj = sku as JObject;
+ if (skuObj == null) continue;
+
+ var estimatePrice = skuObj["estimatePrice"]?.Value() ?? 0;
+ var price = skuObj["price"]?.Value() ?? 0;
+ var actualPrice = estimatePrice > 0 ? estimatePrice : price;
+
+ if (actualPrice > 0 && actualPrice < minPrice)
+ minPrice = actualPrice;
+ }
+
+ return minPrice > 0 && minPrice != decimal.MaxValue ? minPrice / 100 : 0;
+ }
+
+ #endregion
+
+ #region 辅助方法
+
+ private string GetStringValue(JObject obj, string path)
+ {
+ return obj?.SelectToken(path)?.Value() ?? string.Empty;
+ }
+
+ private long GetLongValue(JObject obj, string path)
+ {
+ var token = obj?.SelectToken(path);
+ if (token == null) return 0;
+
+ if (token.Type == JTokenType.String)
+ return long.TryParse(token.Value(), out var result) ? result : 0;
+
+ return token.Value();
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/TEMUKJD/WXForms/ProductForms/WXUserCollectAuthProdListForm.cs b/TEMUKJD/WXForms/ProductForms/WXUserCollectAuthProdListForm.cs
index 14a2714..3e329e4 100644
--- a/TEMUKJD/WXForms/ProductForms/WXUserCollectAuthProdListForm.cs
+++ b/TEMUKJD/WXForms/ProductForms/WXUserCollectAuthProdListForm.cs
@@ -1210,7 +1210,7 @@ namespace TemuKJD.WXForms.ProductForms
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = true;
// 设置过滤条件,只显示文本文件
- openFileDialog.Filter = "文本文件 (*.txt)|*.txt|All files (*.*)|*.*";
+ openFileDialog.Filter = "文本文件 (*.txt;*.json)|*.txt;*.json|All files (*.*)|*.*";
// 显示对话框并获取结果
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
diff --git a/test/KJD.Test/UnitTest1.cs b/test/KJD.Test/UnitTest1.cs
index 17f81b7..c7efb1f 100644
--- a/test/KJD.Test/UnitTest1.cs
+++ b/test/KJD.Test/UnitTest1.cs
@@ -138,6 +138,16 @@ namespace KJD.Test
}
}
+
+
+ [Test]
+ public void TestWXToPDDV4()
+ {
+ string filePath = @"C:\Users\chaih\Documents\xwechat_files\hongfei357_a567\msg\file\2026-10\10000033063024.json";
+ var frontProdInfo = ConverterToPddFactory.Convert(filePath);
+ var isMatch = frontProdInfo != null;
+ Console.WriteLine(frontProdInfo.Skus.Count);
+ }
}
}