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 keyWords = null; private CheckBox chkSelectAll = null; private List lstShopId = new List(); 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 dgvRowList = dgvShop.Rows.Cast().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().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().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 dictionary = new Dictionary(); 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().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 productList = new List(); var waitSetStockHtml = ""; while ((currentNum < operateCount && currentNum < totalNumBase) || page == 0) { page += 1; currentNum += pageSize; if (cancellationTokenSource.IsCancellationRequested) { row = this.dgvShop.Rows.Cast().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().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().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(jObjDataStr); if (addList != null) productList.AddRange(addList); } offSaleMessage = "正在获取商品,第" + currentNum + "件商品,共" + operateCount + "件商品"; Invoke(new Action(() => { row = this.dgvShop.Rows.Cast().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().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().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().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().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().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 dictionary = new Dictionary(); 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 dictionary = new Dictionary(); 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; } } } }