步步为盈
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

317 lines
15 KiB

using BBWY.Client.Extensions;
using BBWY.Client.Models;
using BBWY.Common.Http;
using BBWY.Common.Models;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json.Linq;
using QuanTan.SDK.Client;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
namespace BBWY.Client.APIServices
{
public class PurchaseProductAPIService : IDenpendency
{
private RestApiService restApiService;
private IMemoryCache memoryCache;
private string oneBoundKey = "t5060712539";
private string oneBoundSecret = "20211103";
private string qtAppId = "BBWY2023022001";
private string qtAppSecret = "908e131365d5448ca651ba20ed7ddefe";
private List<string> locationIdList;
private List<string> priceIdList;
private TimeSpan purchaseProductCacheTimeSpan;
//private TimeSpan _1688SessionIdTimeSpan;
//private ConcurrentDictionary<string, (Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)> productChaches;
private IDictionary<string, string> _1688ProductDetailRequestHeader;
private QuanTanProductClient quanTanProductClient;
public PurchaseProductAPIService(RestApiService restApiService, IMemoryCache memoryCache, QuanTanProductClient quanTanProductClient)
{
this.restApiService = restApiService;
this.memoryCache = memoryCache;
_1688ProductDetailRequestHeader = new Dictionary<string, string>()
{
{ "Host","detail.1688.com"},
{ "User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36 Edg/104.0.1293.70"},
{ "Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"},
{ "Accept-Encoding","gzip, deflate, br"},
{ "Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"}
};
purchaseProductCacheTimeSpan = TimeSpan.FromHours(1);
this.quanTanProductClient = quanTanProductClient;
locationIdList = new List<string>()
{
"300252630336272",
"1081181309101",
"16347413030323"
};
priceIdList = new List<string>() {
"300252630336263",
"1081181309582",
"16347413030316"
};
}
public (Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)? GetProductInfo(Platform platform, string productId, string skuId, string purchaseProductId, PurchaseOrderMode priceMode, PurchaseProductAPIMode apiMode)
{
if (memoryCache.TryGetValue<(Purchaser, IList<PurchaseSchemeProductSku>)>($"{purchaseProductId}_{priceMode}", out var tuple))
return tuple.Copy();
(Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)? data = null;
if (apiMode == PurchaseProductAPIMode.Spider)
{
data = LoadFromSpider(platform, productId, skuId, purchaseProductId, priceMode);
if (data == null)
data = LoadFromOneBound(platform, productId, skuId, purchaseProductId, priceMode);
}
else if (apiMode == PurchaseProductAPIMode.OneBound)
{
data = LoadFromOneBound(platform, productId, skuId, purchaseProductId, priceMode);
if (data == null)
data = LoadFromSpider(platform, productId, skuId, purchaseProductId, priceMode);
}
if (data != null)
{
try
{
memoryCache.Set<(Purchaser, IList<PurchaseSchemeProductSku>)>($"{purchaseProductId}_{priceMode}", data.Value, purchaseProductCacheTimeSpan);
}
catch { }
}
return data?.Copy();
}
private (Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)? LoadFromOneBound(Platform platform, string productId, string skuId, string purchaseProductId, PurchaseOrderMode priceMode)
{
try
{
string platformStr = string.Empty;
if (platform == Platform.)
platformStr = "1688";
if (string.IsNullOrEmpty(platformStr))
return null;
var result = restApiService.SendRequest("https://api-gw.onebound.cn/", $"{platformStr}/item_get", $"key={oneBoundKey}&secret={oneBoundSecret}&num_iid={purchaseProductId}&lang=zh-CN&cache=no&agent={(priceMode == PurchaseOrderMode.批发 ? 0 : 1)}", null, HttpMethod.Get, paramPosition: ParamPosition.Query, enableRandomTimeStamp: true);
if (result.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception($"{result.StatusCode} {result.Content}");
var jobject = JObject.Parse(result.Content);
var isOK = jobject.Value<string>("error_code") == "0000";
if (isOK)
{
var skuJArray = (JArray)jobject["item"]["skus"]["sku"];
if (skuJArray.Count == 0)
{
//errorMsg = $"商品{purchaseSchemeProduct.PurchaseProductId}缺少sku信息";
return null;
}
var list = skuJArray.Select(j => new PurchaseSchemeProductSku()
{
ProductId = productId,
SkuId = skuId,
PurchaseProductId = purchaseProductId,
Price = j.Value<decimal>("price"),
PurchaseSkuId = j.Value<string>("sku_id"),
PurchaseSkuSpecId = j.Value<string>("spec_id"),
Title = j.Value<string>("properties_name"),
Logo = GetOneBoundSkuLogo(j, (JArray)jobject["item"]["prop_imgs"]["prop_img"])
}).ToList();
var purchaserId = jobject["item"]["seller_info"].Value<string>("user_num_id");
var purchaserName = jobject["item"]["seller_info"].Value<string>("title");
if (string.IsNullOrEmpty(purchaserName))
purchaserName = jobject["item"]["seller_info"].Value<string>("shop_name");
var purchaserLocation = jobject["item"].Value<string>("location");
return (new Purchaser()
{
Id = purchaserId,
Name = purchaserName,
Location = purchaserLocation
}, list);
}
}
catch { }
{
return null;
}
}
private string GetOneBoundSkuLogo(JToken skuJToken, JArray prop_img)
{
if (!prop_img.HasValues)
return "pack://application:,,,/Resources/Images/defaultItem.png";
var properties = skuJToken.Value<string>("properties").Split(';', StringSplitOptions.RemoveEmptyEntries);
foreach (var p in properties)
{
var imgJToken = prop_img.FirstOrDefault(g => g.Value<string>("properties") == p);
if (imgJToken != null)
return imgJToken.Value<string>("url");
}
return "pack://application:,,,/Resources/Images/defaultItem.png";
}
private (Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)? LoadFromSpider(Platform platform, string productId, string skuId, string purchaseProductId, PurchaseOrderMode priceMode)
{
switch (platform)
{
case Platform.:
return LoadFrom1688Spider(platform, productId, skuId, purchaseProductId, priceMode);
case Platform.:
return LoadFromQTSpider(platform, productId, skuId, purchaseProductId, priceMode);
}
return null;
}
private (Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)? LoadFrom1688Spider(Platform platform, string productId, string skuId, string purchaseProductId, PurchaseOrderMode priceMode)
{
//https://detail.1688.com/offer/672221374773.html?clickid=65f3772cd5d16f190ce4991414607&sessionid=3de47a0c26dcbfde4692064bd55861&sk=order
//globalData/tempModel/sellerUserId
//globalData/tempModel/companyName
//data/1081181309101/data/location
//data/1081181309582/data/pirceModel/[currentPrices]/[0]price
try
{
var _1688pageResult = restApiService.SendRequest("https://detail.1688.com",
$"offer/{purchaseProductId}.html",
$"clickid={Guid.NewGuid().ToString().Md5Encrypt()}&sessionid={Guid.NewGuid().ToString().Md5Encrypt()}&sk={(priceMode == PurchaseOrderMode.批发 ? "order" : "consign")}",
_1688ProductDetailRequestHeader,
HttpMethod.Get,
httpClientName: "gzip");
if (_1688pageResult.StatusCode != System.Net.HttpStatusCode.OK)
return null;
var match = Regex.Match(_1688pageResult.Content, @"(window\.__INIT_DATA\s?=)(.*)(\r*\n*\s*</script>)");
if (!match.Success)
return null;
var jsonStr = match.Groups[2].Value;
var jobject = JObject.Parse(jsonStr);
//16347413030323
var purchaser = new Purchaser()
{
Id = jobject["globalData"]["tempModel"]["sellerUserId"].ToString(),
Name = jobject["globalData"]["tempModel"]["companyName"].ToString()
};
foreach (var lid in locationIdList)
{
if (jobject["data"][lid] != null)
{
purchaser.Location = jobject["data"][lid]["data"]["location"].ToString();
break;
}
}
var colorsProperty = jobject["globalData"]["skuModel"]["skuProps"].FirstOrDefault(j => j.Value<int>("fid") == 3216 ||
j.Value<int>("fid") == 1627207 ||
j.Value<int>("fid") == 1234 ||
j.Value<int>("fid") == 3151)["value"]
.Children()
.Select(j => new
{
name = j.Value<string>("name"),
imageUrl = j.Value<string>("imageUrl")
}).ToList();
//var firstPrice = jobject["data"]["1081181309582"] != null ?
// jobject["data"]["1081181309582"]["data"]["priceModel"]["currentPrices"][0].Value<decimal>("price") :
// jobject["data"]["16347413030316"]["data"]["priceModel"]["currentPrices"][0].Value<decimal>("price");
var firstPrice = 0M;
foreach (var pid in priceIdList)
{
if (jobject["data"][pid] != null)
{
firstPrice = jobject["data"][pid]["data"]["priceModel"]["currentPrices"][0].Value<decimal>("price");
break;
}
}
var purchaseSchemeProductSkus = new List<PurchaseSchemeProductSku>();
foreach (var jsku in jobject["globalData"]["skuModel"]["skuInfoMap"].Children())
{
var jskuProperty = jsku as JProperty;
var name = jskuProperty.Name;
var matchName = name.Contains("&gt;") ? name.Substring(0, name.IndexOf("&gt;")) : name;
var value = jskuProperty.Value;
var skuPrice = value.Value<decimal>("price");
purchaseSchemeProductSkus.Add(new PurchaseSchemeProductSku()
{
ProductId = productId,
SkuId = skuId,
PurchaseProductId = purchaseProductId,
Price = skuPrice == 0M ? firstPrice : skuPrice,
Title = matchName,
PurchaseSkuId = value.Value<string>("skuId"),
PurchaseSkuSpecId = value.Value<string>("specId"),
Logo = colorsProperty.FirstOrDefault(c => c.name == matchName)?.imageUrl ?? "pack://application:,,,/Resources/Images/defaultItem.png"
});
}
return (purchaser, purchaseSchemeProductSkus);
}
catch
{
return null;
}
}
private (Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)? LoadFromQTSpider(Platform platform, string productId, string skuId, string purchaseProductId, PurchaseOrderMode priceMode)
{
try
{
var response = quanTanProductClient.GetProductInfo(purchaseProductId, qtAppId, qtAppSecret);
if (response.Status != 200)
return null;
return (new Purchaser()
{
Id = response.Data.Supplier.VenderId,
Name = response.Data.Supplier.VerdenName,
Location = response.Data.Supplier.Location
}, response.Data.ProductSku.Select(qtsku => new PurchaseSchemeProductSku()
{
ProductId = productId,
SkuId = skuId,
PurchaseProductId = purchaseProductId,
Price = qtsku.Price,
Title = qtsku.Title,
PurchaseSkuId = qtsku.SkuId,
PurchaseSkuSpecId = string.Empty,
Logo = qtsku.Logo
}).ToList());
}
catch
{
return null;
}
}
}
}