344 lines
13 KiB
C#
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;
|
|
}
|
|
}
|