Files
KJD_WebService/TEMUKJD/KJDForms/UploadForms/StockSyncForm.cs
T
2025-06-29 19:38:31 +08:00

605 lines
28 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using AllBase;
using AllBase.Helper;
using AllBase.Model.Result;
using LittleRabbit.Extension;
using LittleRabbit.LittleRabbitForms.BaseForms;
using NaiBa.Util.Extension;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Work.DouyinApiClass;
namespace LittleRabbit.LittleRabbitForms.UploadForms
{
public partial class StockSyncForm : Form
{
private int operateCount = 999999;
private int stock = 99;
private List<string> keyWords = null;
private CheckBox chkSelectAll = null;
private List<string> lstShopId = new List<string>();
public string FailedMessages = "";
CancellationTokenSource cancellationTokenSource = null;
public StockSyncForm()
{
InitializeComponent();
}
private void StockSyncForm_Load(object sender, EventArgs e)
{
chkSelectAll = dgvShop.Columns["colSelect"].AddHeaderCheckBox(HorizontalAlignment.Right, 0, 0, null, null, false);
chkSelectAll.Width = chkSelectAll.Height = 13;
chkSelectAll.CheckedChanged += chkSelectAll_CheckedChanged;
}
private void StockSyncForm_VisibleChanged(object sender, EventArgs e)
{
RefreshShop();
}
private void RefreshShop()
{
// 更新选中的上货店铺Id
lstShopId = lstShopId.Where(id => GlobalConfig.DouShopLoginList.Any(s => s.ShopAccountId == id && s.LoginStatus == "已授权")).ToList();
// 获取被删除的店铺
List<DataGridViewRow> dgvRowList = dgvShop.Rows.Cast<DataGridViewRow>().Where(row
=> !GlobalConfig.DouShopLoginList.Any(s => s.ShopAccountId == row.Cells["colShopId"]?.Value?.ToString())).ToList();
// 更新被删除的店铺列表
foreach (var row in dgvRowList)
{
dgvShop.Rows.Remove(row);
}
// 绑定其他店铺(含新导入的店铺)
foreach (DouShopLoginInfo shopEntity in GlobalConfig.DouShopLoginList)
{
BindShop(shopEntity);
}
}
private void BindShop(DouShopLoginInfo shopEntity)
{
var row = dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(p => p.Cells.GetCellValueFromColumnName("colShopId").ParseToString() == shopEntity.ShopAccountId);
if (row == null)
{
this.dgvShop.Rows.Add(
false,
shopEntity.ShopAccountId,
shopEntity.ShopAccount,
shopEntity.ApiAuthStatus == "授权成功" ? true : false,
"查看详情",
shopEntity.OnlineProductCount >= 0 ? shopEntity.OnlineProductCount.ToString() : "",
shopEntity.OfflineProductCount >= 0 ? shopEntity.OfflineProductCount.ToString() : "",
string.Empty,
string.Empty
);
}
else
{
row.Cells["colSelect"].Value = lstShopId.Contains(shopEntity.ShopAccountId);
row.Cells["colShopName"].Value = shopEntity.ShopAccount;
row.Cells["colCanUse"].Value = shopEntity.ApiAuthStatus == "授权成功" ? true : false;
row.Cells["colOnSaleCount"].Value = shopEntity.OnlineProductCount >= 0 ? shopEntity.OnlineProductCount.ToString() : "";
row.Cells["colOffSaleCount"].Value = shopEntity.OfflineProductCount >= 0 ? shopEntity.OfflineProductCount.ToString() : "";
}
}
private void chkSelectAll_CheckedChanged(object sender, EventArgs e)
{
if (!chkSelectAll.Checked)
{
lstShopId.Clear();
foreach (DataGridViewRow row in dgvShop.Rows)
{
row.Cells["colSelect"].Value = false;
}
}
else
{
lstShopId.Clear();
var list = GlobalConfig.DouShopLoginList.Where(s => s.ApiAuthStatus == "授权成功").Select(ss => ss.ShopAccountId);
lstShopId.AddRange(list);
foreach (DataGridViewRow row in dgvShop.Rows)
{
if (list.Any(l => l == row.Cells["colShopId"]?.Value?.ToString()))
row.Cells["colSelect"].Value = true;
}
}
}
private void btnRefreshShop_Click(object sender, EventArgs e)
{
RefreshShop();
}
private void btnGetProductCount_Click(object sender, EventArgs e)
{
if (lstShopId.Count == 0)
{
BaseMsgForm.ShowInfo("请选择要获取商品数量的店铺");
return;
}
this.btnGetProductCount.Enabled = false;
foreach (DataGridViewRow row in dgvShop.Rows)
{
if (lstShopId.Contains(row.Cells["colShopId"]?.Value))
row.Cells["colStatus"].Value = "";
}
Task.Run(() =>
{
GetShopProduct();
Invoke(new Action(() =>
{
btnGetProductCount.Enabled = true;
BaseMsgForm.ShowInfo("商品数量获取完成");
}));
});
}
void GetShopProduct(bool isShowProgress = true)
{
int i = 0;
var shopList = GlobalConfig.DouShopLoginList.Where(s => s.ApiAuthStatus == "授权成功" && lstShopId.Contains(s.ShopAccountId));
foreach (var shop in shopList)
{
this.Invoke(new Action(() =>
{
i++;
var total = shopList.Count();
if (isShowProgress)
{
this.statusBar.lblTaskStatus.Text = "正在获取...";
this.statusBar.pgbTaskProgress.Value = i;
this.statusBar.pgbTaskProgress.Text = i + "/" + total;
this.statusBar.pgbTaskProgress.Maximum = total;
}
}));
GetShopProduct(shop);
Thread.Sleep(Randomx.GetId(50, 150));
}
Invoke(new Action(() =>
{
if (isShowProgress)
this.statusBar.lblTaskStatus.Text = "获取完成";
}));
}
void GetShopProduct(DouShopLoginInfo shop, bool isShowResult = true)
{
DataGridViewRow row = null;
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null)
{
if (isShowResult)
row.Cells["colStatus"].Value = "正在获取店铺商品数量";
}
}));
// 读取在售商品数量
var resultOnline = GetShopProductListData(shop, 0, 1, 10);
if (resultOnline.Contains("\"code\":10000"))
{
if (row != null)
{
var text = BaseRegex.GetStringJson(ref resultOnline, "total");
shop.OnlineProductCount = text.ParseToInt();
Invoke(new Action(() =>
{
row.Cells["colOnSaleCount"].Value = string.IsNullOrEmpty(text) ? "" : text;
}));
}
}
// 读取下架商品数量
var resultOffline = GetShopProductListData(shop, 1, 1, 10);
if (resultOffline.Contains("\"code\":10000"))
{
if (row != null)
{
var text = BaseRegex.GetStringJson(ref resultOffline, "total");
shop.OfflineProductCount = text.ParseToInt();
Invoke(new Action(() =>
{
row.Cells["colOffSaleCount"].Value = string.IsNullOrEmpty(text) ? "" : text;
}));
}
}
string resultShowText = "";
if (resultOnline.Contains("\"code\":10000") && resultOffline.Contains("\"code\":10000"))
{
resultShowText = "商品数量获取成功";
}
else
{
resultShowText = "商品数量获取失败";
if (!resultOnline.Contains("\"code\":10000"))
{
var html = BaseRegex.GetStringJson(ref resultOnline, "sub_msg");
if (string.IsNullOrEmpty(html))
html = resultOnline;
resultShowText += ",获取在售商品错误:" + html;
}
if (!resultOffline.Contains("\"code\":10000"))
{
var html = BaseRegex.GetStringJson(ref resultOffline, "sub_msg");
if (string.IsNullOrEmpty(html))
html = resultOffline;
resultShowText += ",获取仓库商品错误:" + html;
}
}
Invoke(new Action(() =>
{
if (row != null)
{
if (isShowResult)
row.Cells["colStatus"].Value = resultShowText;
}
}));
}
public string GetShopProductListData(DouShopLoginInfo shop, int productStatus = 0, int page = 1, int pageSize = 50)
{
// 读取在售商品数量
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("page", page.ToString());
dictionary.Add("size", pageSize.ToString());
if (productStatus == 0)
dictionary.Add("check_status", "3");
dictionary["status"] = productStatus.ToString();
DouyinApi douApi = new DouyinApi(shop);
douApi.JsonData = dictionary;
var resultOnline = douApi.GetProductList();
return resultOnline;
}
private void btnStop_Click(object sender, EventArgs e)
{
if (cancellationTokenSource != null)
cancellationTokenSource.Cancel();
}
private void btnSetStock_Click(object sender, EventArgs e)
{
if (lstShopId.Count == 0)
{
BaseMsgForm.ShowInfo("请选择要设置库存的店铺");
return;
}
try
{
stock = txtStockCount.Text.ParseToInt();
this.operateCount = Convert.ToInt32(txtOperateCount.Text);
this.keyWords = txtKeywords.Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
catch (Exception ex)
{
BaseMsgForm.ShowInfo("请输入正确的参数");
return;
}
FailedMessages = "";
this.btnFailedDetail.Visible = false;
this.btnSetStock.Enabled = false;
foreach (DataGridViewRow row in dgvShop.Rows)
{
if (lstShopId.Contains(row.Cells["colShopId"].Value?.ToString()))
row.Cells["colStatus"].Value = "";
}
int n = 0;
cancellationTokenSource = new CancellationTokenSource();
//notClearDate = DateTime.Now.Date.AddDays(0 - this.txtNotOperateDays.ParseToInt());
Task.Run(() =>
{
foreach (var shopId in lstShopId)
{
this.Invoke(new Action(() =>
{
n++;
var total = lstShopId.Count();
this.statusBar.lblTaskStatus.Text = "正在设置库存...";
this.statusBar.pgbTaskProgress.Value = n;
this.statusBar.pgbTaskProgress.Text = n + "/" + total;
this.statusBar.pgbTaskProgress.Maximum = total;
}));
var shop = GlobalConfig.DouShopLoginList.FirstOrDefault(s => s.ShopAccountId == shopId);
if (shop == null)
continue;
DataGridViewRow row = null;
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { row.Cells["colStatus"].Value = "正在设置库存"; }
}));
// 显示商品数
GetShopProduct(shop, false);
int totalNumBase = shop.OnlineProductCount; // 设置开始时的在售商品数
int totalNum = shop.OnlineProductCount; // 在售商品数
int setNum = 0; // 设置商品数量(因关键词存在因此少于或等于商品循环计数)
int currentNum = 0; // 商品循环计数
int page = 0;
int pageSize = 50;
string offSaleMessage = "";
List<DouProductListInfo> productList = new List<DouProductListInfo>();
var waitSetStockHtml = "";
while ((currentNum < operateCount && currentNum < totalNumBase) || page == 0)
{
page += 1;
currentNum += pageSize;
if (cancellationTokenSource.IsCancellationRequested)
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { Invoke(new Action(() => { row.Cells["colStatus"].Value = "下架中断"; })); }
break;
}
// 获取商品列表
waitSetStockHtml = GetShopProductListData(shop, 0, page);
Thread.Sleep(Randomx.GetId(500, 1000));
if (waitSetStockHtml.Contains("\"code\":10000"))
{
totalNum = BaseRegex.GetIntJson(ref waitSetStockHtml, "total");
shop.OfflineProductCount = totalNum;
if (operateCount > totalNumBase)
operateCount = totalNumBase;
if (currentNum > totalNumBase)
currentNum = totalNumBase;
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null)
{
row.Cells["colOnSaleCount"].Value = totalNumBase;
}
}));
if (totalNum == 0)
{
offSaleMessage = "设置结束,店铺没有在售的商品";
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { row.Cells["colStatus"].Value = offSaleMessage; }
}));
break;
}
try
{
JObject jObj = JObject.Parse(waitSetStockHtml);
var jObjDataStr = jObj["data"]?["data"]?.ToString();
if (!string.IsNullOrEmpty(jObjDataStr))
{
var addList = JsonHelper.DeserializeJsonToList<DouProductListInfo>(jObjDataStr);
if (addList != null)
productList.AddRange(addList);
}
offSaleMessage = "正在获取商品,第" + currentNum + "件商品,共" + operateCount + "件商品";
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { row.Cells["colStatus"].Value = offSaleMessage; }
}));
}
catch (Exception ex)
{
BaseMsgForm.ShowError("获取商品发生错误:" + ex.Message);
}
}
else
{
var failMessage = BaseRegex.GetStringJson(ref waitSetStockHtml, "sub_msg");
if (string.IsNullOrEmpty(failMessage))
failMessage = waitSetStockHtml;
offSaleMessage = ("设置库存失败," + failMessage).TrimEnd(',');
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { row.Cells["colStatus"].Value = offSaleMessage; }
}));
}
}
// 有关键词的过滤符合关键词
if (keyWords.Any())
productList = productList.Where(p => keyWords.Any(key => p.name.Contains(key))).ToList();
// 只操作指定天数之前修改的商品
//productList = productList.Where(p => p.update_time < BaseClass.DateTimeToTimestampSeconds(notClearDate)).ToList();
// 操作数大于满足筛选条件商品数时,操作数改为商品数
if (operateCount > productList.Count)
operateCount = productList.Count;
for (int i = 0; i < productList.Count && i < operateCount; i++)
{
if (cancellationTokenSource.IsCancellationRequested)
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { Invoke(new Action(() => { row.Cells["colStatus"].Value = "设置库存中断"; })); }
break;
}
Invoke(new Action(() =>
{
offSaleMessage = "正在设置库存,第 " + (i + 1) + " 件商品,共" + operateCount + "件商品";
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { row.Cells["colStatus"].Value = offSaleMessage; }
}));
Thread.Sleep(50);
var product = productList[i];
setNum++;
var pid = product.product_id;
Thread.Sleep(Randomx.GetId(100, 300));
var productDetail = GetProductDetail(shop, pid.ToString());
if (productDetail == null || productDetail.Contains("spec_prices") == false)
productDetail = "{\"data\":{\"spec_prices\":[]}}";
var skus = JObject.Parse(productDetail)?["data"]?["spec_prices"];
//var skuIds = BaseRegex.GetMatchRegex(ref productDetail, "\"sku_id\":\\d{1,20}");
int num = 0;
foreach (JObject jObj in skus)
{
num++;
var skuStr = JsonHelper.SerializeObject(jObj);
var skuId = BaseRegex.GetLongJson(ref skuStr, "sku_id");
var old_stock = BaseRegex.GetLongJson(ref skuStr, "stock_num");
if (old_stock == stock)
continue;
var offSaleResultCode = SetProductStock(shop, pid.ToString(), skuId.ToString(), stock.ToString());
if (!offSaleResultCode.Contains("\"code\":10000"))
{
Thread.Sleep(Randomx.GetId(1000, 3000));
offSaleResultCode = SetProductStock(shop, pid.ToString(), skuId.ToString(), stock.ToString());
}
Thread.Sleep(Randomx.GetId(50, 150));
if (offSaleResultCode.Contains("\"code\":10000"))
{
LogSave.Add("");
offSaleMessage = "设置库存中,第" + setNum + "件商品,共" + operateCount + "件商品";
Thread.Sleep(Randomx.GetId(50, 150));
}
else
{
var failMessage = BaseRegex.GetStringJson(ref offSaleResultCode, "sub_msg");
if (string.IsNullOrEmpty(failMessage))
failMessage = BaseRegex.GetStringJson(ref offSaleResultCode, "status_reason");
if (string.IsNullOrEmpty(failMessage))
failMessage = offSaleResultCode;
FailedMessages += "店铺:" + shop.ShopAccount + ",商品id:" + pid + ",skuId:" + skuId + ",错误信息:" + failMessage + "\r\n";
offSaleMessage = ("设置库存失败," + failMessage).TrimEnd(',');
Thread.Sleep(10000);
}
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { row.Cells["colStatus"].Value = offSaleMessage; }
}));
Thread.Sleep(Randomx.GetId(100, 200));
if (offSaleMessage.Contains("违规") || offSaleMessage.Contains("禁售"))
continue;
if (offSaleMessage.Contains("失败"))
continue;
}
if (i == operateCount - 1)
{
offSaleMessage = "设置库存完成";
Invoke(new Action(() =>
{
row = this.dgvShop.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells["colShopId"].Value.ToString() == shop.ShopAccountId);
if (row != null) { row.Cells["colStatus"].Value = offSaleMessage; }
}));
}
// 操作过程中更新显示仓库商品数
if (i % 50 == 49 || i == operateCount - 1)
GetShopProduct(shop, false);
}
}
Invoke(new Action(() =>
{
this.btnSetStock.Enabled = true;
if (!cancellationTokenSource.IsCancellationRequested)
{
var text = "设置库存完成!";
if (!string.IsNullOrEmpty(FailedMessages))
{
//text += "部分商品设置库存失败,请查看详情。";
//btnFailedDetail.Visible = true;
}
this.statusBar.lblTaskStatus.Text = text;
BaseMsgForm.ShowInfo(text);
}
else
{
var text = "设置库存中断!";
if (!string.IsNullOrEmpty(FailedMessages))
{
//text += "部分商品设置库存失败,请查看详情。";
//btnFailedDetail.Visible = true;
}
this.statusBar.lblTaskStatus.Text = text;
BaseMsgForm.ShowInfo(text);
}
}));
}, cancellationTokenSource.Token);
}
public string SetProductStock(DouShopLoginInfo shop, string productId, string skuId, string stock)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("product_id", productId);
dictionary.Add("sku_id", skuId);
dictionary.Add("stock_num", stock);
DouyinApi douApi = new DouyinApi(shop);
douApi.JsonData = dictionary;
var resultOnline = douApi.SetProductStock();
return resultOnline;
}
public string GetProductDetail(DouShopLoginInfo shop, string productId)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("product_id", productId);
DouyinApi douApi = new DouyinApi(shop);
douApi.JsonData = dictionary;
var resultOnline = douApi.GetProductDetail();
return resultOnline;
}
private void dgvShop_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex < 0 || e.RowIndex < 0)
return;
string headerText = dgvShop.Columns[e.ColumnIndex].HeaderText;
long shopId = dgvShop.Rows[e.RowIndex].Cells["colShopId"].Value.ParseToLong();
string shopName = dgvShop.Rows[e.RowIndex].Cells["colShopId"].Value.ToString();
var shop = GlobalConfig.DouShopLoginList.FirstOrDefault(s => s.ShopAccountId == shopId.ToString());
switch (headerText)
{
case "操作":
case "选":
if (dgvShop.Rows[e.RowIndex].Cells["colCanuse"].Value.ParseToBool())
{
dgvShop.Rows[e.RowIndex].Cells["colSelect"].Value = !dgvShop.Rows[e.RowIndex].Cells["colSelect"].Value.ParseToBool();
if (dgvShop.Rows[e.RowIndex].Cells["colSelect"].Value.ParseToBool())
lstShopId.Add(shopId.ToString());
else
lstShopId.Remove(shopId.ToString());
}
else
{
BaseMsgForm.ShowInfo("店铺未授权");
}
break;
}
}
}
}