using _29WxOrderWpf.CefHelper; using _29WxOrderWpf.Commands; using AllBase; using CefSharp; using CefSharp.Handler; using CefSharp.Wpf; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using Work._29Tools.CefTools; using WxOrder.Framework.Helpers; namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels; public partial class PDDInvoiceViewModel { /// /// 订单列表浏览器 /// public ChromiumWebBrowser Browser { get; private set; } /// /// 内容浏览器 /// 订单详情 /// 发票详情 /// 申请发票 /// public ChromiumWebBrowser BrowserDetail { get; private set; } partial void InitBrowser() { BrowserZIndex = -1; BrowserDetailZIndex = -1; Browser = WPFCEFBrowser.CreateChromiumWebBrowser("about:blank", false); LocalResourceRequestHandler resourceRequestHandler = new LocalResourceRequestHandler(); //resourceRequestHandler.BeforeResourceLoadEvent += RequestHandler_BeforeResourceLoad; resourceRequestHandler.ResourceLoadCompleteEvent += RequestHandler_ResourceLoadComplete; Browser.RequestHandler = new LocalRequestHandler(resourceRequestHandler); Browser.LifeSpanHandler = new LocalLifeSpanHandler(PopWindowType.SelfWindow); Browser.KeyboardHandler = new KeyboardHandler(); Browser.LoadingStateChanged += Browser_LoadingStateChanged; BrowserDetail = WPFCEFBrowser.CreateChromiumWebBrowser("about:blank", false); LocalResourceRequestHandler detailResourceRequestHandler = new LocalResourceRequestHandler(); detailResourceRequestHandler.ResourceLoadCompleteEvent += DetailRequestHandler_ResourceLoadComplete; BrowserDetail.RequestHandler = new LocalRequestHandler(resourceRequestHandler); BrowserDetail.LifeSpanHandler = new LocalLifeSpanHandler(PopWindowType.SelfWindow); BrowserDetail.KeyboardHandler = new KeyboardHandler(); BrowserDetail.LoadingStateChanged += BrowserDetail_LoadingStateChanged; } private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) { if (e.IsLoading == false) { var b = (ChromiumWebBrowser)sender; b.Dispatcher.InvokeAsync(async () => { if (b.Address != null && b.Address.StartsWith("https://mobile.yangkeduo.com/orders.html")) { StartAutoScroll(); } }); } } private void BrowserDetail_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) { if (e.IsLoading == false) { var b = (ChromiumWebBrowser)sender; b.Dispatcher.InvokeAsync(async () => { if (b.Address != null && b.Address.StartsWith("https://mobile.yangkeduo.com/transac_return_compensation.html")) { string html = await b.GetBrowser().GetSourceAsync(); if (html.Contains("window.rawData")) { await ExecuteInvoiceApplyScriptAsync(b); } else { // 页面异常(未渲染出发票表单)时直接判定失败,避免批量开票长时间等待 _currentInvoiceTcs?.TrySetResult(false); } } }); } } /// /// 注入发票填写脚本并执行。 /// 单张申请模式保持原有行为;批量开票模式下轮询脚本写入的 /// window.__invoiceApplyResult,完成后通过 回传结果。 /// private async Task ExecuteInvoiceApplyScriptAsync(ChromiumWebBrowser b) { string content = ResourceHelper.GetResourceText("/Ctrls/PDDInvoice/Resources/invoice.js", "29WxFindOrder"); content = content.Replace("{公司}", Config.Title); content = content.Replace("{税号}", Config.TaxNo); if (string.IsNullOrEmpty(content)) return; await b.EvaluateScriptAsync(content); if (_currentInvoiceTcs == null) return; // 单张申请模式:保持原有行为 // 批量模式:等待异步脚本执行完成 // 捕获当前 TCS,避免批量循环超时进入下一个订单后,迟到的轮询误触发新订单的结果 var tcs = _currentInvoiceTcs; for (int i = 0; i < 120; i++) { await Task.Delay(500); try { var res = await b.EvaluateScriptAsync("window.__invoiceApplyResult"); if (res.Success && res.Result != null) { tcs.TrySetResult(Convert.ToBoolean(res.Result)); return; } } catch { } } tcs.TrySetResult(false); } public ICommand CloseInvoiceDetailCommand => new DelegateCommand(HidenOrderBrowserDetail); public int BrowserZIndex { get => GetValue(); set => SetValue(value); } public int BrowserDetailZIndex { get => GetValue(); set => SetValue(value); } /// /// 显示主浏览器 /// public void ShowOrderBrowser() { BrowserZIndex = 10; BrowserDetailZIndex = -1; } /// /// 显示子浏览器 /// public void ShowOrderBrowserDetail() { BrowserZIndex = -1; BrowserDetailZIndex = 10; } public void HidenOrderBrowser() { BrowserZIndex = -1; } public void HidenOrderBrowserDetail() { BrowserDetailZIndex = -1; } public bool IsReadOrder { get => GetValue(); set => SetValue(value); } private int top = 0; private DateTime lastGetOrderDataTime = DateTime.Now; private void RequestHandler_ResourceLoadComplete(object sender, string url, string postData, string responseData, IRequest request) { if (url.StartsWith("https://mobile.yangkeduo.com/orders.html")) { //if (isAutoScroll == false) //{ // StartAutoScroll(); //} StartAutoScroll(); } if (url.StartsWith("https://mobile.yangkeduo.com/proxy/api/api/aristotle/order_list_v")) { lastGetOrderDataTime = DateTime.Now; parserData(responseData); //File.WriteAllText(@$"E:\{Guid.NewGuid().ToString()}.txt", responseData); } } public void StartAutoScroll() { if (IsReadOrder) return; IsReadOrder = true; _ = autoScroll(_cancellationTokenSource.Token); } // 停止滚动 public void StopAutoScroll() { IsReadOrder = false; _cancellationTokenSource?.Cancel(); } private async Task autoScroll(CancellationToken token) { while (IsReadOrder && !token.IsCancellationRequested) { if ((DateTime.Now - lastGetOrderDataTime).Seconds > 30) StopAutoScroll(); top += Randomx.GetId(450, 600); var jsStr = @"window.scroll({ top: " + top + @", left: 0, behavior: 'smooth' // 可选,使滚动平滑 });"; var client = Browser.GetDevToolsClient(); if (client != null) { var result = client.Runtime.EvaluateAsync(jsStr, null, true, null, null, true, null, true); result.Wait(5000); } await Task.Delay(Randomx.GetId(100, 300)); //Thread.Sleep(); } } private void DetailRequestHandler_ResourceLoadComplete(object sender, string url, string postData, string responseData, IRequest request) { if (url.StartsWith("https://mobile.yangkeduo.com/transac_return_compensation.html")) { } } }