Files
KJD/Store.Product/Publish/Steps/Wx/BuildSkuPropertiesStep.cs
T
2026-09-14 09:16:59 +08:00

344 lines
13 KiB
C#

using AllBase;
using AllBase.Extension;
using NaiBa.Util.Extension;
using AllBase.Helper;
using AllBase.Model.Config;
using AllBase.Model.DBModel;
using AllBase.Model.Param.WXParam;
using AllBase.Model.Result;
using AllBase.Model.Result.PDDResult;
using AllBase.Model.Result.WXResult;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Store.Product.Models.PublishParameters.Wx;
using Store.Product.Publish;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Work;
namespace Store.Product.Publish.Steps.Wx;
/// <summary>
/// 由 WXDBProdUploadForm.UploadProduct 的“构建SKU规格属性”区段迁移。
/// TODO(迁移): 原区段中的 TEMUKJD/WXUpload/窗体服务引用需按 Store.Product 运行时适配逐项核对。
/// </summary>
public sealed class BuildSkuPropertiesStep : WxProductPublishStepBase
{
public override string Description => "构建SKU规格属性";
protected override Task ExecuteProvider(WXPublishContext context, CancellationToken cancellationToken)
{
if (context.Progress != null)
{
Invoke(new Action(() =>
{
context.Progress.Report("正在生成sku");
}));
}
Thread.Sleep(Randomx.GetId(100, 300));
context.Parameters.ProductParameter.product.info.productSaleAttrs = new List<productSaleAttrParam>();
if (context.Parameters.ProdInfo.detail.sku == null)
context.Parameters.ProdInfo.detail.sku = new List<sku_item>();
if (context.Parameters.ProdInfo.detail.sku.Count == 0)
context.Parameters.ProdInfo.detail.sku.Add(new sku_item() { spec = new List<spec_item>() });
if (context.Parameters.ProdInfo.detail.sku.FirstOrDefault().spec == null)
context.Parameters.ProdInfo.detail.sku.FirstOrDefault().spec = new List<spec_item>();
if (context.Parameters.ProdInfo.detail.sku.FirstOrDefault().spec.Count == 0)
context.Parameters.ProdInfo.detail.sku.FirstOrDefault().spec.Add(new spec_item() { parent_name = "规格", spec_name = "默认" });
if (context.Parameters.ProdInfo.detail.sku.FirstOrDefault().thumb_url.IsNullOrEmpty())
context.Parameters.ProdInfo.detail.sku.FirstOrDefault().thumb_url = context.Parameters.ProdInfo.detail.galleries.FirstOrDefault(g => g.type == 1)?.url;
context.Parameters.MaxSkuSpecCnt = context.Parameters.ProdInfo.detail.sku.Max(x => x.spec?.Count).ParseToInt();
foreach (var skuTmp in context.Parameters.ProdInfo.detail.sku.ToList())
{
if (skuTmp.spec?.Count != context.Parameters.MaxSkuSpecCnt)
context.Parameters.ProdInfo.detail.sku.Remove(skuTmp);
}
// 处理系统指定的规格名称
//if ((upProdParam.product.info.category.FirstOrDefault()?.name == "食品饮料" || prodInfo.detail.cats.FirstOrDefault() == "食品饮料") &&
// (selectProd.cat_name == "坚果炒货" || selectProd.cat_name == "果干"))
//{
// if (!prodInfo.detail.sku.FirstOrDefault().spec.Any(s => s.parent_name == "规格/净含量"))
// {
// foreach (var sku in prodInfo.detail.sku)
// {
// sku.spec.FirstOrDefault().parent_name = "规格/净含量";
// }
// }
//}
////else if ((upProdParam.product.info.category.FirstOrDefault()?.name == "食品饮料" || prodInfo.detail.cats.FirstOrDefault() == "食品饮料"))
////{
//// if (!prodInfo.detail.sku.FirstOrDefault().spec.Any(s => s.parent_name == "规格"))
//// {
//// foreach (var sku in prodInfo.detail.sku)
//// {
//// sku.spec.FirstOrDefault().parent_name = "规格";
//// }
//// }
////}
// 坚果炒货类,系统返回的试规格/净含量但是要求填规格
if ((context.Parameters.ProductParameter.product.info?.category?.FirstOrDefault()?.name == "食品饮料" || context.Parameters.ProdInfo.detail?.cats?.FirstOrDefault() == "食品饮料") &&
(context.Parameters.ProductParameter.product.info?.category?.LastOrDefault()?.name == "坚果炒货" || context.Parameters.ProductParameter.product.info?.category?.LastOrDefault()?.name == "果干"))
{
if (!context.Parameters.ProdInfo.detail.sku.FirstOrDefault().spec.Any(s => s.parent_name == "规格"))
{
foreach (var sku in context.Parameters.ProdInfo.detail.sku)
{
sku.spec.FirstOrDefault().parent_name = "规格";
}
}
}
else
{
var leafCat = context.Parameters.ProductParameter.product.info.category.LastOrDefault();
if (leafCat?.catInfo?.saleAttr?.attr != null)
{
foreach (var att in leafCat.catInfo.saleAttr.attr)
{
//decimal4_unit //g;kg;斤
if (att.isRequired == true)
{
// 规格属性名放在第二个规格上
if (att.normalRelease.ruleType == 2 && context.Parameters.ProdInfo.detail.sku.FirstOrDefault()?.spec.Count == 2)
{
foreach (var sku in context.Parameters.ProdInfo.detail.sku)
{
// 如果有指定规格属性名称就不再设置
if (!sku.spec.Any(sp => sp.parent_name == att.name))
{
sku.spec[1].parent_name = att.name;
}
// 如果不在指定位置上,交换位置
else if (sku.spec[0].parent_name == att.name)
{
var specTmp = sku.spec[0];
sku.spec[0] = sku.spec[1];
sku.spec[1] = specTmp;
}
if (att.type == "decimal4_unit")
{
if (att.value == "g;kg;斤")
{
var specName = "";
foreach (var unit in att.value.Split(';').Reverse().ToList())
{
Match specMatch = Regex.Match(sku.spec[1].spec_name.Replace(" ", "").Replace("-", "负号"), @"\d+(.\d+)?" + unit);
//Match specMatch = Regex.Match(sku.spec[1].spec_name.Replace(" ", ""), @"((0{1}.\d{1,4})|([1-9]\d{1}.\d{1,4})|([1-9]+\d)|0)" + unit);
if (specMatch.Success)
{
specName = specMatch.Value.Replace(unit, "")/*.ParseToDecimal().ParseToInt()*/ + " " + unit;
break;
}
}
if (string.IsNullOrEmpty(specName))
specName = Randomx.GetId(10, 500) + " g";
sku.spec[1].spec_name = specName;
}
}
}
}
// 规格属性名放在第一个规格上
else
{
foreach (var sku in context.Parameters.ProdInfo.detail.sku)
{
// 如果有指定规格属性名称就不再设置
if (!sku.spec.Any(sp => sp.parent_name == att.name))
{
sku.spec[0].parent_name = att.name;
}
// 如果不在指定位置上,交换位置
else if (sku.spec.Count > 1 && sku.spec[1].parent_name == att.name)
{
var specTmp = sku.spec[0];
sku.spec[0] = sku.spec[1];
sku.spec[1] = specTmp;
}
if (att.type == "decimal4_unit")
{
if (att.value == "g;kg;斤")
{
var specName = "";
foreach (var unit in att.value.Split(';').Reverse().ToList())
{
Match specMatch = Regex.Match(sku.spec[0].spec_name.Replace(" ", "").Replace("-", "负号"), @"\d+(.\d+)?" + unit);
//Match specMatch = Regex.Match(sku.spec[0].spec_name.Replace(" ", ""), @"((0{1}.\d{1,4})|([1-9]\d{1}.\d{1,4})|([1-9]+\d)|0)" + unit);
if (specMatch.Success)
{
specName = specMatch.Value.Replace(unit, "")/*.ParseToDecimal().ParseToInt()*/ + " " + unit;
break;
}
}
if (string.IsNullOrEmpty(specName))
specName = Randomx.GetId(10, 500) + " g";
sku.spec[0].spec_name = specName;
}
}
}
}
}
}
}
}
if (context.Parameters.ProdInfo.detail.sku.FirstOrDefault()?.spec?.Count > 0)
{
productSaleAttrParam attrParam = new productSaleAttrParam()
{
key = context.Parameters.ProdInfo.detail.sku.FirstOrDefault()?.spec[0].parent_name,
hasImg = true,
items = new List<productSaleAttrItemParam>()
};
context.Parameters.ProductParameter.product.info.productSaleAttrs.Add(attrParam);
foreach (var sku in context.Parameters.ProdInfo.detail.sku)
{
var spec = sku.spec[0];
if (!attrParam.items.Any(it => it.value == spec.spec_name) && !string.IsNullOrEmpty(sku.thumb_url))
{
if (context.Product.ProductGetTypeText == "微信店采")
{
attrParam.items.Add(new productSaleAttrItemParam() { value = spec.spec_name, imgUrl = sku.thumb_url, });
continue;
}
// 获取缓存盗链 sku图
if (context.Parameters.WxImgMapDic.ContainsKey(BaseClass.GetMd5(sku.thumb_url)))
{
attrParam.items.Add(new productSaleAttrItemParam() { value = spec.spec_name, imgUrl = context.Parameters.WxImgMapDic[BaseClass.GetMd5(sku.thumb_url)], });
continue;
}
// 使用接口链接传sku图
if (1 == 1 && !sku.thumb_url.Contains("wst.wxapp.tc.qq.com"))
{
var urlImg = BaseClass.BuildWXImgObjString("product/wx_api_upload_image");
var upDate = UserLogin.GetSignaturex();
upDate += "&token=" + context.Parameters.Token.accessToken;
upDate += "&post_data=" + GetHtml.UrlEncodeUtf8("{\"img_url\":\"" + sku.thumb_url.Replace("https://", "http://") + "\"}");
var sTime = DateTime.Now;
var upDateRst = GetHtml.PostUtf8(urlImg, upDate);
if (context.Progress != null)
{
Invoke(new Action(() =>
{
context.Progress.Report("正在生成sku " + (DateTime.Now - sTime).TotalMilliseconds.ParseToInt());
}));
}
for (int i = 0; i < 20 && upDateRst.Contains("access_token expired"); i++)
{
context.Parameters.Token.mdyTime = DateTime.Now.AddDays(-100);
context.Parameters.Token = new WxApiBLL().GetRandomWxToken();
upDateRst = GetHtml.PostUtf8(urlImg, upDate);
}
var upImgUrl = BaseRegex.GetStringJson(ref upDateRst, "img_url");
if (upDateRst.Contains("\"errcode\":0") && !string.IsNullOrEmpty(upImgUrl))
{
attrParam.items.Add(new productSaleAttrItemParam() { value = spec.spec_name, imgUrl = upImgUrl, });
context.Parameters.WxImgMapDic[BaseClass.GetMd5(sku.thumb_url)] = upImgUrl;
context.Parameters.IsChangeImgDic = true;
continue; // 传图成功跳过模拟上传
}
else
{
}
}
// api上传图片文件 sku图
if (1 == 1)
{
try
{
string errMsg = "";
var imgBase64 = GetImgBase64ForApi(out errMsg, sku.thumb_url, false, false);
if (!string.IsNullOrEmpty(errMsg))
{
throw new Exception(errMsg);
}
var urlImg = BaseClass.BuildWXImgObjString("product/wx_api_upload_image");
var upDate = UserLogin.GetSignaturex();
upDate += "&token=" + context.Parameters.Token.accessToken;
//upDate += "&is_file=true";
//if (needAddRandomBlock || wantAddRandomBlock)
// upDate += "&random_code=true";
upDate += "&img_url=" + sku.thumb_url;
upDate += "&img_base64=" + imgBase64;
var sTime = DateTime.Now;
var apiUpImgFileRst = GetHtml.PostUtf8(urlImg, upDate);
if (context.Progress != null)
{
Invoke(new Action(() =>
{
context.Progress.Report("正在上传商品sku图文件 " + (DateTime.Now - sTime).TotalMilliseconds.ParseToInt());
}));
}
for (int i = 0; i < 5 && apiUpImgFileRst.Contains("access_token expired"); i++)
{
context.Parameters.Token.mdyTime = DateTime.Now.AddDays(-100);
context.Parameters.Token = new WxApiBLL().GetRandomWxToken();
apiUpImgFileRst = GetHtml.PostUtf8(urlImg, upDate);
}
var upImgUrl = BaseRegex.GetStringJson(ref apiUpImgFileRst, "img_url");
if (apiUpImgFileRst.Contains("\"errcode\":0") && !string.IsNullOrEmpty(upImgUrl))
{
attrParam.items.Add(new productSaleAttrItemParam() { value = spec.spec_name, imgUrl = upImgUrl, });
context.Parameters.WxImgMapDic[BaseClass.GetMd5(sku.thumb_url)] = upImgUrl;
context.Parameters.IsChangeImgDic = true;
continue;
}
else
{
}
}
catch (Exception ex)
{
throw new Exception("修改详情图失败 " + ex.Message);
}
}
// 上传sku图
var locationStr = UploadImg(context.Parameters.Shop, sku.thumb_url);
if (!locationStr.Contains("\"success\":true"))
throw new Exception(locationStr);
var location = BaseRegex.GetStringJson(ref locationStr, "Location");
attrParam.items.Add(new productSaleAttrItemParam() { value = spec.spec_name, imgUrl = location, });
Thread.Sleep(Randomx.GetId(10, 50));
//wxImgMapDic[BaseClass.GetMd5(sku.thumb_url)] = location;
//isChangeImgDic = true;
}
}
}
if (context.Parameters.ProdInfo.detail.sku.FirstOrDefault()?.spec?.Count > 1)
{
productSaleAttrParam attrParam = new productSaleAttrParam()
{
key = context.Parameters.ProdInfo.detail.sku.FirstOrDefault()?.spec[1].parent_name,
hasImg = false,
items = new List<productSaleAttrItemParam>()
};
context.Parameters.ProductParameter.product.info.productSaleAttrs.Add(attrParam);
foreach (var sku in context.Parameters.ProdInfo.detail.sku)
{
var spec = sku.spec[1];
if (!attrParam.items.Any(it => it.value == spec.spec_name))
attrParam.items.Add(new productSaleAttrItemParam() { value = spec.spec_name });
}
}
return Task.CompletedTask;
}
}