using Store.Modules.CloudProduct.Entities; using Store.Modules.CloudProduct.Enums; using System.Text.Json.Nodes; namespace Store.Modules.CloudProduct.ImportConverters { /// /// PDD 前端商品详情数据转换器(数据源格式见 data.txt) /// internal class PddGoodsConverter : GoodsConverter { public override string ConverterName => nameof(PddGoodsConverter); public override PlatformType Platform => PlatformType.PDD; protected override bool IsMatchCore() { try { if (JsonNode.Parse(RawData) is not JsonObject root) return false; // data.txt:顶层包含 goods.goods_id if (root["goods"] is JsonObject goodsObj && goodsObj["goods_id"] != null) return true; // 也兼容顶层直接是商品对象的情况 if (root["goods_id"] != null && (root["goods_name"] != null || root["title"] != null)) return true; return false; } catch { return false; } } protected override GoodsEntity ConvertCore() { if (JsonNode.Parse(RawData) is not JsonObject root) throw new Exception("无法解析 PDD 商品数据"); var goodsNode = root["goods"] as JsonObject ?? root; var priceNode = root["price"] as JsonObject; var goods = new GoodsEntity { Platform = (byte)PlatformType.PDD, GoodsId = GetLong(goodsNode, "goods_id"), Title = GetString(goodsNode, "goods_name") ?? GetString(goodsNode, "short_name") ?? string.Empty, Description = GetString(goodsNode, "share_desc") ?? GetString(goodsNode, "short_name"), ThumbUrl = GetString(goodsNode, "hd_url") ?? GetString(goodsNode, "thumb_url") ?? GetString(goodsNode, "hd_thumb_url") ?? GetString(goodsNode, "image_url"), CatId1 = GetIntOrNull(goodsNode, "cat_id_1"), CatId2 = GetIntOrNull(goodsNode, "cat_id_2"), CatId3 = GetIntOrNull(goodsNode, "cat_id_3"), CatId4 = GetIntOrNull(goodsNode, "cat_id_4"), SoldQuantity = GetInt(goodsNode, "sold_quantity"), Status = 0, }; var price = GetPriceRange(priceNode, root); goods.MinPrice = price.Min; goods.MaxPrice = price.Max; return goods; } private static string? GetString(JsonObject? obj, string key) { if (obj == null || !obj.TryGetPropertyValue(key, out var node) || node == null) return null; if (node is JsonValue value && value.TryGetValue(out var str)) return str; return node.ToJsonString(); } private static long GetLong(JsonObject? obj, string key) { if (obj == null || !obj.TryGetPropertyValue(key, out var node) || node == null) return 0; if (node is JsonValue value) { if (value.TryGetValue(out var l)) return l; if (value.TryGetValue(out var d)) return (long)d; if (long.TryParse(value.ToString(), out var l2)) return l2; } return 0; } private static int GetInt(JsonObject? obj, string key) { if (obj == null || !obj.TryGetPropertyValue(key, out var node) || node == null) return 0; if (node is JsonValue value) { if (value.TryGetValue(out var i)) return i; if (value.TryGetValue(out var l)) return (int)l; if (int.TryParse(value.ToString(), out var i2)) return i2; } return 0; } private static int? GetIntOrNull(JsonObject? obj, string key) { if (obj == null || !obj.TryGetPropertyValue(key, out var node) || node == null) return null; if (node is JsonValue value) { if (value.TryGetValue(out var i) && i > 0) return i; if (value.TryGetValue(out var l) && l > 0) return (int)l; if (int.TryParse(value.ToString(), out var i2) && i2 > 0) return i2; } return null; } private static long? GetLongOrNull(JsonObject? obj, string key) { if (obj == null || !obj.TryGetPropertyValue(key, out var node) || node == null) return null; if (node is JsonValue value) { if (value.TryGetValue(out var d)) return d; if (value.TryGetValue(out var l)) return l; if (long.TryParse(value.ToString(), out var d2)) return d2; } return null; } /// /// 计算价格区间。优先使用顶层 price 节点,其次遍历 sku。 /// private static (long? Min, long? Max) GetPriceRange(JsonObject? priceNode, JsonObject root) { long? min = null; long? max = null; if (priceNode != null) { min = GetLongOrNull(priceNode, "min_group_price"); max = GetLongOrNull(priceNode, "max_group_price"); if (min.HasValue || max.HasValue) return (min, max); } if (root["sku"] is JsonArray skuArray && skuArray.Count > 0) { foreach (var item in skuArray.OfType()) { var price = GetLongOrNull(item, "group_price") ?? GetLongOrNull(item, "normal_price"); if (price == null) continue; min = min.HasValue ? Math.Min(min.Value, price.Value) : price; max = max.HasValue ? Math.Max(max.Value, price.Value) : price; } if (min.HasValue || max.HasValue) return (min, max); } return (null, null); } } }