using _29WxOrderWpf.CefHelper; using _29WxOrderWpf.Commands; using AllBase; using AllBase.Helper; using AllBase.Model.DBModel; using AllBase.Model.Result; using AllBase.Util; using CefSharp; using CefSharp.Handler; using CefSharp.Wpf; using NaiBa.Util.Extension; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Runtime; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Threading; using Work._29Tools.CefTools; using WPFCommon.Models; namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels; /// /// 拼多多发票助手 视图模型 /// public partial class PDDInvoiceViewModel : BindableBaseEx { private readonly ObservableCollection _allOrders = new(); private readonly HashSet _orderSns = new(); private string _searchText = ""; private PddBrowserOrderInvoiceViewModel _selectedOrder; private bool _isInvoiceDialogOpen; private bool _isInvoiceDetailOpen; private string _invoiceType = "电子普通发票"; private string _invoiceTitle = "XX科技有限公司"; private string _taxNo = "91110000XXXXXXXXXX"; private CancellationTokenSource _cancellationTokenSource; public PDDInvoiceViewModel() { Orders = new ObservableCollection(); BuyerLoginList = GlobalConfig.PDDBuyerLoginList; //Orders = new ObservableCollection(_allOrders); //_ = InitSampleData(); InitBrowser(); } partial void InitBrowser(); private void parserData(string data) { List list = JsonHelper.DeserializeJsonToList(JsonHelper.JObjectParse(data)["orders"].ParseToString()); if (list.Count == 0) { StopAutoScroll(); return; } var matched = list.Where(item => item.status == 4 && item.pay_status == 2).ToList(); if (matched.Count == 0) { return; } // CEF 回调运行在后台线程,ObservableCollection 的更新需要切回 UI 线程 var dispatcher = Application.Current?.Dispatcher; if (dispatcher == null || dispatcher.CheckAccess()) { AddOrders(matched); } else { dispatcher.BeginInvoke(new Action(() => AddOrders(matched))); } } /// 将新订单写入总表,并按当前搜索关键字决定是否加入可见列表(自动去重) private void AddOrders(IEnumerable items) { var keyword = SearchText?.Trim(); foreach (var item in items) { if (!string.IsNullOrEmpty(item.order_sn) && !_orderSns.Add(item.order_sn)) { continue; } _allOrders.Add(item); if (IsKeywordMatch(item, keyword)) { Orders.Add(item); } } } public ObservableCollectionThreadSafe BuyerLoginList { get; set; } = new ObservableCollectionThreadSafe(); public BuyerLoginInfo SelectedBuyer { get => GetProperty(() => SelectedBuyer); set => SetProperty(() => SelectedBuyer, value, SelectedBuyerChanged); } private void SelectedBuyerChanged() { WPFCEFBrowser.SetCookieAsync(SelectedBuyer.cookie, Browser.GetCookieManager()).GetAwaiter(); WPFCEFBrowser.SetCookieAsync(SelectedBuyer.cookie, BrowserDetail.GetCookieManager()).GetAwaiter(); } /// 订单列表 public ObservableCollection Orders { get; } /// 搜索关键字:订单号 / 商品名称 / 买家 public string SearchText { get => _searchText; set => SetProperty(ref _searchText, value, nameof(SearchText)); } /// 开票弹窗是否打开 public bool IsInvoiceDialogOpen { get => _isInvoiceDialogOpen; set => SetProperty(ref _isInvoiceDialogOpen, value, nameof(IsInvoiceDialogOpen)); } /// 发票详情弹窗是否打开 public bool IsInvoiceDetailOpen { get => _isInvoiceDetailOpen; set => SetProperty(ref _isInvoiceDetailOpen, value, nameof(IsInvoiceDetailOpen)); } /// 当前操作的订单 public PddBrowserOrderInvoiceViewModel SelectedOrder { get => _selectedOrder; set => SetProperty(ref _selectedOrder, value, nameof(SelectedOrder)); } /// 开票类型 public string InvoiceType { get => _invoiceType; set => SetProperty(ref _invoiceType, value, nameof(InvoiceType)); } /// 发票抬头 public string InvoiceTitle { get => _invoiceTitle; set => SetProperty(ref _invoiceTitle, value, nameof(InvoiceTitle)); } /// 税号 public string TaxNo { get => _taxNo; set => SetProperty(ref _taxNo, value, nameof(TaxNo)); } public ICommand SearchCommand => new DelegateCommand(Search); public ICommand ResetCommand => new DelegateCommand(ResetSearch); public ICommand OpenInvoiceCommand => new DelegateCommand(OpenInvoice); public ICommand ShowInvoiceCommand => new DelegateCommand(ShowInvoice); public ICommand ViewOrderCommand => new DelegateCommand(ViewOrder); public ICommand CloseInvoiceDialogCommand => new DelegateCommand(() => IsInvoiceDialogOpen = false); public ICommand ConfirmInvoiceCommand => new DelegateCommand(ConfirmInvoice); public ICommand ReadOrderCommand => new DelegateCommand(ReadOrder, () => !IsAutoScroll); private void ReadOrder() { Browser.Load("https://mobile.yangkeduo.com/orders.html"); ShowOrderBrowser(); } /// 按 订单号 / 商品名称 过滤订单 private void Search() { var keyword = SearchText?.Trim(); Orders.Clear(); foreach (var order in _allOrders.Where(o => IsKeywordMatch(o, keyword))) { Orders.Add(order); } } private static bool IsKeywordMatch(PddBrowserOrderInvoiceViewModel order, string keyword) { return string.IsNullOrEmpty(keyword) || (!string.IsNullOrEmpty(order.order_sn) && order.order_sn.Contains(keyword)) || (!string.IsNullOrEmpty(order.GoodsName) && order.GoodsName.Contains(keyword)); } private void ResetSearch() { SearchText = ""; Search(); } private void OpenInvoice(PddBrowserOrderInvoiceViewModel order) { SelectedOrder = order; BrowserDetail.Load($"https://mobile.yangkeduo.com/transac_return_compensation.html?_t_timestamp=transac_modify_invoice&order_sn={order.order_sn}"); ShowOrderBrowserDetail(); //InvoiceType = string.IsNullOrEmpty(order.InvoiceType) ? "电子普通发票" : order.InvoiceType; //InvoiceTitle = string.IsNullOrEmpty(order.InvoiceTitle) ? "XX科技有限公司" : order.InvoiceTitle; //TaxNo = string.IsNullOrEmpty(order.TaxNo) ? "91110000XXXXXXXXXX" : order.TaxNo; //IsInvoiceDialogOpen = true; } private void ConfirmInvoice() { if (SelectedOrder == null) return; //SelectedOrder.IsInvoiced = true; //SelectedOrder.InvoiceType = InvoiceType; //SelectedOrder.InvoiceTitle = InvoiceTitle; //SelectedOrder.TaxNo = TaxNo; //SelectedOrder.InvoiceNo = "25" + DateTime.Now.ToString("MMddHHmmss"); //SelectedOrder.InvoiceAmountText = SelectedOrder.AmountText; //SelectedOrder.InvoiceTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); IsInvoiceDialogOpen = false; //MessageBox.Show($"订单 {SelectedOrder.OrderNo} 开票成功"); } private void ShowInvoice(PddBrowserOrderInvoiceViewModel order) { SelectedOrder = order; IsInvoiceDetailOpen = true; } private void ViewOrder(PddBrowserOrderInvoiceViewModel order) { //MessageBox.Show($"查看订单:{order.OrderNo}"); } /// /// 原型演示数据(后续可替换为真实接口数据) /// private Task InitSampleData() { string directoryPath = @"E:\820"; // 3. 获取所有 txt 文件 var txtFiles = Directory.GetFiles(directoryPath, "*.txt"); if (txtFiles.Length == 0) { Console.WriteLine("未找到任何 .txt 文件"); return Task.CompletedTask; } foreach (var filePath in txtFiles) { try { string jsonContent = File.ReadAllText(filePath); parserData(jsonContent); } catch (Exception ex) { } } return Task.CompletedTask; } #region 进度条 private string _bottomMsg = ""; public string BottomMsg { get => _bottomMsg; set => SetValue(ref _bottomMsg, value); } private double _progressValue; public double ProgressValue { get => _progressValue; set => SetValue(ref _progressValue, value); } private double _progressMaximum = 100; public double ProgressMaximum { get => _progressMaximum; set => SetValue(ref _progressMaximum, value); } public void SetProgress(int value, int maxValue) { StopUnknownTotalProgressTimer(); ProgressValue = value; ProgressMaximum = maxValue; } #region 未知总数百分比模拟进度 private System.Threading.Timer _unknownTotalProgressTimer; private DateTime _unknownTotalProgressStartTime; /// /// 开始未知总数的百分比模拟进度:80% 之前走得快,越到最后走得越慢, /// 理论上永远走不到 95% 以上,直到调用 才会变成 100%。 /// public void StartProgress() { StopUnknownTotalProgressTimer(); ProgressMaximum = 100; ProgressValue = 0; _unknownTotalProgressStartTime = DateTime.Now; _unknownTotalProgressTimer = new System.Threading.Timer(_ => UpdateUnknownTotalProgress(), null, 0, 200); } /// /// 结束进度:停止模拟,进度条立即变为 100%。 /// public void CompleteProgress() { StopUnknownTotalProgressTimer(); ProgressMaximum = 100; ProgressValue = 100; } private void UpdateUnknownTotalProgress() { try { System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => { var elapsed = (DateTime.Now - _unknownTotalProgressStartTime).TotalSeconds; double progress; if (elapsed <= 10) { // 前 10 秒内快速推进到 80% progress = Math.Max(0, Math.Min(80, elapsed * 8)); } else { // 超过 80% 后指数衰减越来越慢,渐近线为 95%,理论上永远走不到 95% 以上 progress = 95.0 - 15.0 * Math.Exp(-(elapsed - 10.0) / 20.0); } if (progress > 95) progress = 95; ProgressValue = progress; })); } catch { } } private void StopUnknownTotalProgressTimer() { if (_unknownTotalProgressTimer == null) return; try { _unknownTotalProgressTimer.Dispose(); } catch { } _unknownTotalProgressTimer = null; } #endregion #endregion }