From 75aae91b66592054b808b81e54f506a4206df7df Mon Sep 17 00:00:00 2001 From: wule Date: Fri, 16 Oct 2026 10:11:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8B=8D=E5=8D=95=20=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BC=82=E5=B8=B8=E6=8B=8D=E5=8D=95=E5=92=8C?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E4=B8=8D=E5=87=86=E7=A1=AE=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E6=8B=A6=E6=88=AA=E9=80=80=E5=9B=9E=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BuyerCtrls/TaobaoBuyOrderCtrl.xaml.cs | 14 +-- .../BuyerCtrls/TaobaoBuyOrderViewModel.cs | 16 ++++ .../ViewModels/TaobaoLoginViewModel.cs | 93 ++++++++++++++++++- .../TransitAfterSaleWindow.xaml.cs | 13 ++- .../Model/DBModel/oms_wei_order_item_info.cs | 12 ++- Work/_29Tools/Forms/PddMobileBuyOrderForm.cs | 7 +- 6 files changed, 130 insertions(+), 25 deletions(-) diff --git a/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderCtrl.xaml.cs b/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderCtrl.xaml.cs index 37f6545..227e10d 100644 --- a/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderCtrl.xaml.cs +++ b/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderCtrl.xaml.cs @@ -60,19 +60,7 @@ public partial class TaobaoBuyOrderCtrl : UserControl private void ParentWindow_Closed(object sender, EventArgs e) { - // 1. 解除 JS 绑定 - this.ViewModel?.CefWebBrowser?.JavascriptObjectRepository?.UnRegisterAll(); - //this.ViewModel.CefWebBrowser?.CloseDevTools(); - - // 2. 优雅关闭浏览器 - this.ViewModel?.CefWebBrowser?.GetBrowser()?.CloseBrowser(false); - - // 3. 清理残留子进程(按路径判断,避免误杀) - //CleanupBrowserSubprocesses(); - - // 4. 释放控件 - this.ViewModel?.CefWebBrowser?.Dispose(); - //this.ViewModel.CefWebBrowser = null; + ViewModel.Stop(); } private void ViewModel_BrowserCreated(ChromiumWebBrowser browser) diff --git a/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderViewModel.cs b/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderViewModel.cs index 5180fdd..3bae314 100644 --- a/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderViewModel.cs +++ b/29WxOrderWpf/Ctrls/BuyerCtrls/TaobaoBuyOrderViewModel.cs @@ -17,6 +17,8 @@ using Newtonsoft.Json.Linq; using Org.BouncyCastle.Asn1.Ocsp; using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; using System.Drawing; using System.Linq; using System.Security.Policy; @@ -440,6 +442,20 @@ namespace _29WxOrderWpf.Ctrls.BuyerCtrls public void Stop() { _isWindowLoaded = false; + + // 1. 解除 JS 绑定 + CefWebBrowser?.JavascriptObjectRepository?.UnRegisterAll(); + CefWebBrowser?.CloseDevTools(); + + // 2. 优雅关闭浏览器 + CefWebBrowser?.GetBrowser()?.CloseBrowser(false); + + // 3. 清理残留子进程(按路径判断,避免误杀) + TaobaoLoginViewModel.CleanupBrowserSubprocesses(); + + // 4. 释放控件 + CefWebBrowser?.Dispose(); + CefWebBrowser = null; } /// diff --git a/29WxOrderWpf/ViewModels/TaobaoLoginViewModel.cs b/29WxOrderWpf/ViewModels/TaobaoLoginViewModel.cs index 1118888..bf76597 100644 --- a/29WxOrderWpf/ViewModels/TaobaoLoginViewModel.cs +++ b/29WxOrderWpf/ViewModels/TaobaoLoginViewModel.cs @@ -11,6 +11,8 @@ using NaiBa.Util.Extension; using Org.BouncyCastle.Asn1.Ocsp; using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; using System.Linq; using System.Security.Policy; using System.Text; @@ -35,6 +37,8 @@ namespace _29WxOrderWpf.ViewModels // 拼多多买手退货退款售后地址 // https://mobile.yangkeduo.com/complaint.html?order_sn=260718-101481213440980&after_sales_reason=0&after_sales_type=2&after_sales_code=1002 + List cefSubProcesses = new List(); + public static TaobaoLoginViewModel TaobaoLoginInstance { get; set; } = null; /// 浏览器创建完成后触发(视图在此把浏览器加入可视树) @@ -160,7 +164,6 @@ namespace _29WxOrderWpf.ViewModels } Task.Run(() => { - AutoLogin(); }); } @@ -171,6 +174,90 @@ namespace _29WxOrderWpf.ViewModels public void Stop() { _isWindowLoaded = false; + + // 1. 解除 JS 绑定 + CefWebBrowser?.JavascriptObjectRepository?.UnRegisterAll(); + CefWebBrowser?.CloseDevTools(); + + // 2. 优雅关闭浏览器 + CefWebBrowser?.GetBrowser()?.CloseBrowser(false); + + // 3. 清理残留子进程(按路径判断,避免误杀) + CleanupBrowserSubprocesses(this.cefSubProcesses); + + // 4. 释放控件 + CefWebBrowser?.Dispose(); + CefWebBrowser = null; + } + + public static void CleanupBrowserSubprocesses(List processes = null) + { + // 有可能释放错误导致程序崩溃,废弃 + return; + try + { + if (processes == null) + processes = new List(); + + string appBasePath = AppDomain.CurrentDomain.BaseDirectory.TrimEnd('\\', '/'); + Process[] subprocesses = Process.GetProcessesByName("CefSharp.BrowserSubprocess"); + + foreach (Process process in subprocesses) + { + bool shouldKill = false; + try + { + // 安全地获取进程模块信息,进程可能在我们检查时已退出 + if (process != null && !process.HasExited) + { + string moduleFileName = process.MainModule?.FileName; + if (!string.IsNullOrEmpty(moduleFileName)) + { + // 判断进程是否从当前应用目录启动 + string processDir = System.IO.Path.GetDirectoryName(moduleFileName); + if (!string.IsNullOrEmpty(processDir) && + (processDir.Equals(appBasePath, StringComparison.OrdinalIgnoreCase) + || appBasePath.Contains(processDir) // 处理子目录情况 + || moduleFileName.Contains(appBasePath))) + { + if (!processes.Any(p => p.Handle.ParseToInt() == process.Handle.ParseToInt())) + shouldKill = true; + } + } + } + } + catch (InvalidOperationException) + { + // 进程可能在检查过程中已退出,忽略 + continue; + } + catch (Win32Exception ex) when (ex.NativeErrorCode == 5) // 访问被拒绝 + { + // 可能是权限问题或其他应用的进程,跳过 + continue; + } + + if (shouldKill) + { + try + { + process.Kill(); + process.WaitForExit(500); // 等待最多500毫秒,确保进程终止 + } + catch (Exception killEx) + { + // 记录日志,但通常进程已死 + //System.Diagnostics.Debug.WriteLine($"终止进程时出错: {killEx.Message}"); + } + } + } + } + catch (Exception ex) + { + // 这里最好不要用MessageBox,尤其是在关闭流程中,可能引发线程问题 + // 建议记录到日志文件 + //System.Diagnostics.Debug.WriteLine($"清理子进程时发生异常: {ex}"); + } } /// @@ -184,6 +271,8 @@ namespace _29WxOrderWpf.ViewModels { if (CefWebBrowser == null) { + this.cefSubProcesses = Process.GetProcessesByName("CefSharp.BrowserSubprocess").ToList(); + if (!string.IsNullOrEmpty(InitUrl)) CefWebBrowser = WPFCEFBrowser.CreateChromiumWebBrowser(InitUrl, false); else @@ -223,7 +312,7 @@ namespace _29WxOrderWpf.ViewModels while (!CefWebBrowser.IsBrowserInitialized || !CefWebBrowser.GetBrowser().MainFrame.IsValid) await Task.Delay(20); - await WPFCEFBrowser.DeleteCookieAsync(CefWebBrowser.GetCookieManager(null)); + //await WPFCEFBrowser.DeleteCookieAsync(CefWebBrowser.GetCookieManager(null)); //cef 138 如果没有设置RequestContext 可能为空,直接getCookieManager //await WPFCEFBrowser.SetCookieAsync(JsonHelper.SerializeObject(cookieLst), CefWebBrowser.GetCookieManager(null)); diff --git a/29WxOrderWpf/Windows/OrderWindows/TransitAfterSaleWindow.xaml.cs b/29WxOrderWpf/Windows/OrderWindows/TransitAfterSaleWindow.xaml.cs index b262380..3dff0ec 100644 --- a/29WxOrderWpf/Windows/OrderWindows/TransitAfterSaleWindow.xaml.cs +++ b/29WxOrderWpf/Windows/OrderWindows/TransitAfterSaleWindow.xaml.cs @@ -55,8 +55,8 @@ namespace _29WxOrderWpf.Windows.OrderWindows if (OrderItem != null) { this.cmbWareHouse.Text = TransitWarehouseData.TransitWarehouseList.FirstOrDefault(t => t.TransId == OrderItem.ItemTransitOrderWithVoid?.platform)?.TransName; - this.txtExpressName.Text = OrderItem.ItemTransitOrder?.express_2_company; - this.txtWarehouseWaybill.Text = OrderItem.ItemTransitOrder?.express_2_waybill; + this.txtExpressName.Text = OrderItem.ItemTransitOrder?.express_2_company ?? OrderItem.ItemTransitOrderWithVoid?.express_2_company; + this.txtWarehouseWaybill.Text = OrderItem.ItemTransitOrder?.express_2_waybill ?? OrderItem.ItemTransitOrderWithVoid?.express_2_waybill; if (OrderItem.ItemTransitOrderAfterSale != null) { @@ -151,7 +151,7 @@ namespace _29WxOrderWpf.Windows.OrderWindows JObject data = new JObject(); data["orderNo"] = OrderItem.order_id; - data["orderCode"] = OrderItem.ItemTransitOrder?.order_code; + data["orderCode"] = OrderItem.ItemTransitOrderWithVoid?.order_code; data["refundProvince"] = txtProvince.Text.Trim(); data["refundCity"] = txtCity.Text.Trim(); data["refundCounty"] = txtCounty.Text.Trim(); @@ -251,12 +251,15 @@ namespace _29WxOrderWpf.Windows.OrderWindows { if (OrderItem.ItemTransitOrder?.warehouse_status == 3) return "\"success\":true,\"message\":\"已到仓,无需拦截工单\""; + if (OrderItem.ItemTransitOrderWithVoid?.warehouse_status == 3) + return "\"success\":true,\"message\":\"已到仓,无需拦截工单\""; string url = HttpResponseTransitWorkOrderBLL.WorkOrderUrl + "/api/open/v1/customer-work-orders/intercept-return-cloud-warehouse-after-outbound"; JObject obj = new JObject(); - obj["appId"] = this.OrderItem.Shop.ShopId; + obj["appId"] = this.OrderItem.Shop?.ShopId; obj["wechatOrderNo"] = this.OrderItem.order_id; - obj["purchaseOrderNo"] = this.OrderItem.PddBuyerAfterSale?.orderSn; + //obj["purchaseOrderNo"] = this.OrderItem.PddBuyerAfterSale?.orderSn; + obj["purchaseOrderNo"] = OrderItem.ItemTransitOrderWithVoid?.order_code; obj["creator"] = BaseClass.UserName; obj["remark"] = "客户要求拦截并退回云仓"; diff --git a/AllBase/Model/DBModel/oms_wei_order_item_info.cs b/AllBase/Model/DBModel/oms_wei_order_item_info.cs index 014aa65..646aced 100644 --- a/AllBase/Model/DBModel/oms_wei_order_item_info.cs +++ b/AllBase/Model/DBModel/oms_wei_order_item_info.cs @@ -331,10 +331,16 @@ namespace AllBase.Model.DBModel this.TransitOrderWaybillFakeStr = ItemTransitOrder.express_1_company + "-" + ItemTransitOrder.express_1_waybill; // 仓库下游物流 - if (ItemTransitOrder == null || ItemTransitOrder.express_2_company.IsNullOrEmpty() || ItemTransitOrder.express_2_waybill.IsNullOrEmpty()) - TransitOrderWaybillFromWareHouseStr = null; + //if (ItemTransitOrder == null || ItemTransitOrder.express_2_company.IsNullOrEmpty() || ItemTransitOrder.express_2_waybill.IsNullOrEmpty()) + // TransitOrderWaybillFromWareHouseStr = null; + //else + // TransitOrderWaybillFromWareHouseStr = ItemTransitOrder.express_2_company + "-" + ItemTransitOrder.express_2_waybill; + if (ItemTransitOrder != null && !ItemTransitOrder.express_2_company.IsNullOrEmpty() && !ItemTransitOrder.express_2_waybill.IsNullOrEmpty()) + TransitOrderWaybillFromWareHouseStr = ItemTransitOrder.express_2_company + "-" + ItemTransitOrder.express_2_waybill; + else if (ItemTransitOrderWithVoid != null && !ItemTransitOrderWithVoid.express_2_company.IsNullOrEmpty() && !ItemTransitOrderWithVoid.express_2_waybill.IsNullOrEmpty()) + TransitOrderWaybillFromWareHouseStr = ItemTransitOrderWithVoid.express_2_company + "-" + ItemTransitOrderWithVoid.express_2_waybill; else - TransitOrderWaybillFromWareHouseStr = ItemTransitOrder.express_2_company + "-" + ItemTransitOrder.express_2_waybill; + TransitOrderWaybillFromWareHouseStr = null; if (order_id == "3739043283864307968") { diff --git a/Work/_29Tools/Forms/PddMobileBuyOrderForm.cs b/Work/_29Tools/Forms/PddMobileBuyOrderForm.cs index 04982da..9f822e3 100644 --- a/Work/_29Tools/Forms/PddMobileBuyOrderForm.cs +++ b/Work/_29Tools/Forms/PddMobileBuyOrderForm.cs @@ -650,8 +650,9 @@ namespace TemuKJD.ToolForms Task.Run(async () => { // 自动下单 - while (true && IsAutoBuy) + while (this.Created && IsAutoBuy) { + Thread.Sleep(100); if (HasChangeAddress && (this.cefWebBrowser?.GetMainFrame()?.Url).ParseToString().StartsWith("https://mobile.yangkeduo.com/order_checkout.html?sku_id=")) { try @@ -935,7 +936,7 @@ namespace TemuKJD.ToolForms } })();"; } - for (int i = 0; i < 20; i++) + for (int i = 0; i < 30; i++) { Thread.Sleep(100); if (!this.Created) @@ -1831,6 +1832,8 @@ namespace TemuKJD.ToolForms /// private void CleanupBrowserSubprocesses() { + // 有可能释放错误导致程序崩溃,废弃 + return; try { string appBasePath = AppDomain.CurrentDomain.BaseDirectory.TrimEnd('\\', '/');