From f2d31c4a42b0334c6458844157d3f7b6c050434c Mon Sep 17 00:00:00 2001 From: chfei Date: Thu, 20 Aug 2026 14:56:38 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=8F=91=E7=A5=A8=E5=8A=A9=E6=89=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ImageUrlToBitmapImageConverter.cs | 28 +- .../Ctrls/OrderCtrls/OrderListCtrl.Command.cs | 318 +++++++ .../Ctrls/OrderCtrls/OrderListCtrl.xaml | 42 +- .../Ctrls/OrderCtrls/OrderListCtrl.xaml.cs | 273 +----- .../Ctrls/PDDInvoice/PDDInvoiceView.xaml | 800 ++++++++++++++++++ .../Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs | 37 + .../ViewModels/PDDInvoiceOrderModel.cs | 70 ++ .../ViewModels/PDDInvoiceViewModel.Browser.cs | 168 ++++ .../ViewModels/PDDInvoiceViewModel.cs | 391 +++++++++ .../Statistics/ShopRevenueStatisticsView.xaml | 27 +- 10 files changed, 1850 insertions(+), 304 deletions(-) create mode 100644 29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs create mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml create mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs create mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs create mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs create mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs diff --git a/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs b/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs index dfbf7e4..2063aaf 100644 --- a/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs +++ b/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -14,27 +15,38 @@ namespace _29WxOrderWpf.Converters { public class ImageUrlToBitmapImageConverter : IValueConverter { + /// 缓存上限,防止大量缩略图重复下载导致内存膨胀 + private const int MaxCacheCount = 200; + + private readonly ConcurrentDictionary _imageCache = new ConcurrentDictionary(); + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is string url && Uri.IsWellFormedUriString(url, UriKind.Absolute)) { + if (_imageCache.TryGetValue(url, out BitmapImage cached)) + { + return cached; + } + try { // 直接加载绑定如果遇到有问题的网络图片会直接崩溃。 - //var bitMap = new BitmapImage(new Uri(url)); - BitmapImage bitMap = null; - //bitMap = LoadImageFromUrl(url + "?imageView2/1/w/100/format/webp|imageMogr2/auto-orient="); - bitMap = AllBase.ImageBuild.LoadBitmipImageFromUrl(url); + BitmapImage bitMap = AllBase.ImageBuild.LoadBitmipImageFromUrl(url); + if (bitMap != null) + { + if (_imageCache.Count >= MaxCacheCount) + { + _imageCache.Clear(); + } + _imageCache[url] = bitMap; + } return bitMap; - //string errStr = ""; - //var bitmapImg = GetUrlImg(url, out errStr); - //return bitmapImg; } catch { } - //return Task.Run(() => new BitmapImage(new Uri(url))); // 使用 Task.Run 来异步加载图片。 } return null; } diff --git a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs new file mode 100644 index 0000000..6625d74 --- /dev/null +++ b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs @@ -0,0 +1,318 @@ +using _29WxOrderWpf.BaseWindows; +using _29WxOrderWpf.Commands; +using _29WxOrderWpf.Common; +using _29WxOrderWpf.Ctrls.PDDInvoice; +using _29WxOrderWpf.Ctrls.Statistics; +using _29WxOrderWpf.Services; +using AllBase.Helper; +using AllBase.Model.DBModel; +using NaiBa.Util.Extension; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using Work._29Tools.BLL; +using static _29WxOrderWpf.Services.ShipGiftService; + +namespace _29WxOrderWpf.Ctrls.OrderCtrls; + +public partial class OrderListCtrl +{ + #region 统计 + private DialogWindow _statisticsDialog; + public ICommand ShowShopRevenueStatisticsDialogViewCommand => new DelegateCommand(ShowShopRevenueStatisticsDialogView); + + private void ShowShopRevenueStatisticsDialogView() + { + if (_statisticsDialog == null) + { + _statisticsDialog = new DialogWindow() + { + Title = "统计", + Content = new ShopRevenueStatisticsView(), + + }; + _statisticsDialog.Closed += (s, e) => _statisticsDialog = null; + } + _statisticsDialog.Show(); + } + #endregion + + #region 礼物 + public ICommand MultipleShipGiftCommand => new AsyncDelegateCommand(MultipleShipGift); + /// + /// 批量发送礼品单 + /// + /// + /// + + private async Task MultipleShipGift() + { + + try + { + var list = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList(); + int count = list.Count; + if (count == 0) + { + BaseMsgWindow.ShowError("请选取要发货的订单", "Error"); + return; + } + + + GiftType giftType = GiftType._160; + if (cb_gift.SelectedIndex == 0) + { + giftType = GiftType._155; + } + else + { + giftType = GiftType._160; + } + int index = 1; + int sucessCount = 0; + int errorCount = 0; + foreach (oms_wei_order_info item in list) + { + try + { + var rst = await WxApiBLL.WxSearchAndDropshipCancelAsync(item.Shop, item); + if (rst == "success") + { + var ret = await _shipGiftService.Send(item.order_id, giftType); + if (ret) + { + sucessCount++; + item.gift_order_status = 1; + this.FilterOneOrder(item, true); + } + else + { + errorCount++; + } + } + else + { + errorCount++; + } + } + catch (Exception ex) + { + errorCount++; + } + finally + { + item.IsSelect = false; + } + + SetProgress(index, count); + BottomMsg = $"礼品单发送进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}"; + index++; + } + + BottomMsg = $"礼品单发送完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}"; + } + catch (Exception ex) + { + BaseMsgWindow.ShowError("礼品单发货失败\n" + ex.Message, "Error"); + } + finally + { + + } + } + #endregion + #region 同步订单 + /// + /// 拉取微信订单到任务列表 + /// + public ICommand PullWXOrderCommand => new AsyncDelegateCommand(PullWXOrder); + + private async Task PullWXOrder() + { + try + { + var isAfterSales = GlobalConfig.OrderTabHeaderStr.StartsWith("需处理售后单");//是否售后 + + var selectedShops = GlobalConfig.ShopLoginList.Where(a => a.IsSelect).ToList(); + if (selectedShops.Count == 0) + { + selectedShops = GlobalConfig.ShopLoginList.ToList(); + } + + var selectedOrders = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList(); + int count = selectedOrders.Count; + if (count > 0 && isAfterSales == false)//非售后订单 + { + if (BaseMsgWindow.ShowConfirm($"已选取:{count}个订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; + BottomMsg = $"订单同步进度...."; + int index = 1; + int sucessCount = 0; + int errorCount = 0; + foreach (var item in selectedOrders) + { + var ret = await PullWXOrderService.Instance.PullOrderDetailAsync(item.shop_id, item.order_id); ; + if (ret) + { + sucessCount++; + this.GetOrder(item.order_id); + SetProgress(index, count); + item.IsSelect = false; + } + else + { + errorCount++; + } + BottomMsg = $"订单同步进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}"; + index++; + } + BottomMsg = $"订单同步进度完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}"; + } + else if (count > 0 && isAfterSales == true)//售后订单 + { + if (BaseMsgWindow.ShowConfirm($"已选取:{count}个售后订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; + //var dictionaryResult = selectedOrders + // .Where(o => o?.refundItems != null) + // .SelectMany(o => o.refundItems + // .Where(item => item != null) + // .Select(item => new { o.shop_id, item.after_sale_order_id })) + // .GroupBy(x => x.shop_id) + // .ToDictionary( + // g => g.Key, + // g => g.Select(x => x.after_sale_order_id).ToArray() + // ); + + + //BottomMsg = $"售后订单同步进度...."; + //foreach (var item in dictionaryResult) + //{ + // var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(item.Key, item.Value); + //} + //BottomMsg = $"售后同步任务已发送,等待同步完成"; + + + + int index = 1; + int sucessCount = 0; + int errorCount = 0; + BottomMsg = $"售后订单同步进度...."; + foreach (KeyValuePair> item in selectedOrders.GroupBy(a => a.shop_id).ToDictionary(a => a.Key, a => a.ToList())) + { + long shopid = item.Key; + string shopName = item.Value.FirstOrDefault()?.shop_name ?? ""; + string[] afterSaleOrderIds = item.Value.SelectMany(a => a.refundItems).Where(a => a != null).Select(a => a.after_sale_order_id).ToArray(); + var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(shopid, afterSaleOrderIds); + if (ret) + { + sucessCount++; + SetProgress(index, count); + item.Value.ForEach(a => a.IsSelect = false); + } + else + { + errorCount++; + } + BottomMsg = $"售后订单同步进度:{index}/{count}\t\t{shopName}"; + index++; + + } + BottomMsg = $"售后同步任务已发送,等待同步完成"; + } + else + { + count = selectedShops.Count; + string prefix = $"已选取:{count}个商铺"; + if (count == GlobalConfig.ShopLoginList.Count) + { + prefix = "已选取全部商铺"; + } + + + var startTime = dateStart.SelectedDate.Value; + var endTime = dateEnd.SelectedDate.Value; + + string msg = ""; + if (isAfterSales) + { + msg = $"{prefix}"; + } + else + { + msg = $"{prefix}\n\n时间范围:{startTime.ToString("yyyy-MM-dd")}-{endTime.ToString("yyyy-MM-dd")}"; + } + + if (BaseMsgWindow.ShowConfirm(msg, $"{(isAfterSales ? "售后" : "")}同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; + + if ((endTime - startTime).Days > 7) + { + throw new Exception("时间范围最大7天"); + } + + var ret = false; + if (isAfterSales) + { + ret = await PullWXOrderService.Instance.PullRefundOrderByShopsAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime); + } + else + { + ret = await PullWXOrderService.Instance.PullOrderByShopIdsAndTimeRangeAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime); + } + if (ret) + { + BaseMsgWindow.ShowInfo("同步任务已发送,等待同步完成\n任务详情查看任务列表"); + } + else + { + BaseMsgWindow.ShowError("同步任务失败"); + } + } + + + } + catch (Exception ex) + { + BaseMsgWindow.ShowError("同步订单失败\n" + ex.Message, "Error"); + } + //var service = PullWXOrderService.Instance; + //foreach (var item in list) + //{ + // await service.PullOrderDetailAsync(item.shop_id, item.order_id); + //} + } + #endregion + #region 显示任务列表 + private DialogWindow _taskDialog; + public ICommand ShowTaskDialogViewCommand => new DelegateCommand(ShowTaskDialogView); + + private void ShowTaskDialogView() + { + if (_taskDialog == null) + { + _taskDialog = new DialogWindow() + { + Title = "任务列表", + Content = new OrderTaskDialogView(), + + }; + _taskDialog.Closed += (s, e) => _taskDialog = null; + } + _taskDialog.Show(); + } + #endregion + + #region 拼多多发票 + public ICommand ShowPDDInvoiceDialogCommand => new DelegateCommand(ShowPDDInvoiceDialog); + + private void ShowPDDInvoiceDialog() + { + new DialogWindow + { + Title = "发票助手", + Content = new PDDInvoiceView() + }.ShowDialog(); + } + #endregion +} diff --git a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml index c36abb5..129ea92 100644 --- a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml +++ b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml @@ -25,7 +25,8 @@ - + + @@ -40,11 +41,8 @@ - - - - + @@ -205,7 +203,8 @@ Padding="4" Click="btnFilter_Click" Content="过滤" - Style="{StaticResource BasePageButtonStyle}" /> + Style="{StaticResource BasePageButtonStyle}" + ToolTip="过滤" /> - + _statisticsWindow = null; - } - _statisticsWindow.Show(); - - } + /// /// @@ -2066,263 +2051,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls // set => SetProperty(ref _IsShipGift, value); //} - public ICommand MultipleShipGiftCommand => new AsyncDelegateCommand(MultipleShipGift); - /// - /// 批量发送礼品单 - /// - /// - /// - private async Task MultipleShipGift() - { - - try - { - var list = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList(); - int count = list.Count; - if (count == 0) - { - BaseMsgWindow.ShowError("请选取要发货的订单", "Error"); - return; - } - - - GiftType giftType = GiftType._160; - if (cb_gift.SelectedIndex == 0) - { - giftType = GiftType._155; - } - else - { - giftType = GiftType._160; - } - int index = 1; - int sucessCount = 0; - int errorCount = 0; - foreach (oms_wei_order_info item in list) - { - try - { - var rst = await WxApiBLL.WxSearchAndDropshipCancelAsync(item.Shop, item); - if (rst == "success") - { - var ret = await _shipGiftService.Send(item.order_id, giftType); - if (ret) - { - sucessCount++; - item.gift_order_status = 1; - this.FilterOneOrder(item, true); - } - else - { - errorCount++; - } - } - else - { - errorCount++; - } - } - catch (Exception ex) - { - errorCount++; - } - finally - { - item.IsSelect = false; - } - - SetProgress(index, count); - BottomMsg = $"礼品单发送进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}"; - index++; - } - - BottomMsg = $"礼品单发送完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}"; - } - catch (Exception ex) - { - BaseMsgWindow.ShowError("礼品单发货失败\n" + ex.Message, "Error"); - } - finally - { - - } - } - - /// - /// 拉取微信订单到任务列表 - /// - public ICommand PullWXOrderCommand => new AsyncDelegateCommand(PullWXOrder); - - private async Task PullWXOrder() - { - try - { - var isAfterSales = GlobalConfig.OrderTabHeaderStr.StartsWith("需处理售后单");//是否售后 - - var selectedShops = GlobalConfig.ShopLoginList.Where(a => a.IsSelect).ToList(); - if (selectedShops.Count == 0) - { - selectedShops = GlobalConfig.ShopLoginList.ToList(); - } - - var selectedOrders = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList(); - int count = selectedOrders.Count; - if (count > 0 && isAfterSales == false)//非售后订单 - { - if (BaseMsgWindow.ShowConfirm($"已选取:{count}个订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; - BottomMsg = $"订单同步进度...."; - int index = 1; - int sucessCount = 0; - int errorCount = 0; - foreach (var item in selectedOrders) - { - var ret = await PullWXOrderService.Instance.PullOrderDetailAsync(item.shop_id, item.order_id); ; - if (ret) - { - sucessCount++; - this.GetOrder(item.order_id); - SetProgress(index, count); - item.IsSelect = false; - } - else - { - errorCount++; - } - BottomMsg = $"订单同步进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}"; - index++; - } - BottomMsg = $"订单同步进度完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}"; - } - else if (count > 0 && isAfterSales == true)//售后订单 - { - if (BaseMsgWindow.ShowConfirm($"已选取:{count}个售后订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; - //var dictionaryResult = selectedOrders - // .Where(o => o?.refundItems != null) - // .SelectMany(o => o.refundItems - // .Where(item => item != null) - // .Select(item => new { o.shop_id, item.after_sale_order_id })) - // .GroupBy(x => x.shop_id) - // .ToDictionary( - // g => g.Key, - // g => g.Select(x => x.after_sale_order_id).ToArray() - // ); - - - //BottomMsg = $"售后订单同步进度...."; - //foreach (var item in dictionaryResult) - //{ - // var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(item.Key, item.Value); - //} - //BottomMsg = $"售后同步任务已发送,等待同步完成"; - - - - int index = 1; - int sucessCount = 0; - int errorCount = 0; - BottomMsg = $"售后订单同步进度...."; - foreach (KeyValuePair> item in selectedOrders.GroupBy(a => a.shop_id).ToDictionary(a => a.Key, a => a.ToList())) - { - long shopid = item.Key; - string shopName = item.Value.FirstOrDefault()?.shop_name ?? ""; - string[] afterSaleOrderIds = item.Value.SelectMany(a => a.refundItems).Where(a => a != null).Select(a => a.after_sale_order_id).ToArray(); - var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(shopid, afterSaleOrderIds); - if (ret) - { - sucessCount++; - SetProgress(index, count); - item.Value.ForEach(a => a.IsSelect = false); - } - else - { - errorCount++; - } - BottomMsg = $"售后订单同步进度:{index}/{count}\t\t{shopName}"; - index++; - - } - BottomMsg = $"售后同步任务已发送,等待同步完成"; - } - else - { - count = selectedShops.Count; - string prefix = $"已选取:{count}个商铺"; - if (count == GlobalConfig.ShopLoginList.Count) - { - prefix = "已选取全部商铺"; - } - - - var startTime = dateStart.SelectedDate.Value; - var endTime = dateEnd.SelectedDate.Value; - - string msg = ""; - if (isAfterSales) - { - msg = $"{prefix}"; - } - else - { - msg = $"{prefix}\n\n时间范围:{startTime.ToString("yyyy-MM-dd")}-{endTime.ToString("yyyy-MM-dd")}"; - } - - if (BaseMsgWindow.ShowConfirm(msg, $"{(isAfterSales ? "售后" : "")}同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; - - if ((endTime - startTime).Days > 7) - { - throw new Exception("时间范围最大7天"); - } - - var ret = false; - if (isAfterSales) - { - ret = await PullWXOrderService.Instance.PullRefundOrderByShopsAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime); - } - else - { - ret = await PullWXOrderService.Instance.PullOrderByShopIdsAndTimeRangeAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime); - } - if (ret) - { - BaseMsgWindow.ShowInfo("同步任务已发送,等待同步完成\n任务详情查看任务列表"); - } - else - { - BaseMsgWindow.ShowError("同步任务失败"); - } - } - - - } - catch (Exception ex) - { - BaseMsgWindow.ShowError("同步订单失败\n" + ex.Message, "Error"); - } - //var service = PullWXOrderService.Instance; - //foreach (var item in list) - //{ - // await service.PullOrderDetailAsync(item.shop_id, item.order_id); - //} - } - - private DialogWindow _taskDialog; - public ICommand ShowTaskDialogViewCommand => new DelegateCommand(ShowTaskDialogView); - - private void ShowTaskDialogView() - { - if (_taskDialog == null) - { - _taskDialog = new DialogWindow() - { - Title = "任务列表", - Content = new OrderTaskDialogView(), - - }; - _taskDialog.Closed += (s, e) => _taskDialog = null; - } - _taskDialog.Show(); - } } public class OrderFilterConfig diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml b/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml new file mode 100644 index 0000000..7efeba5 --- /dev/null +++ b/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml @@ -0,0 +1,800 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs b/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs new file mode 100644 index 0000000..0e640ac --- /dev/null +++ b/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs @@ -0,0 +1,37 @@ +using _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace _29WxOrderWpf.Ctrls.PDDInvoice; + +/// +/// PDDInvoiceView.xaml 的交互逻辑 +/// +public partial class PDDInvoiceView : UserControl +{ + public PDDInvoiceView() + { + InitializeComponent(); + DataContext = new PDDInvoiceViewModel(); + } + + private void txtSearch_KeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter && DataContext is PDDInvoiceViewModel viewModel) + { + viewModel.SearchCommand.Execute(null); + } + } +} \ No newline at end of file diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs new file mode 100644 index 0000000..128ff3a --- /dev/null +++ b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs @@ -0,0 +1,70 @@ +using AllBase.Model.Result; +using System; +using System.Collections.Generic; +using System.Linq; +using WPFCommon.Helpers; +using WPFCommon.Models; + +namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels; + +/// +/// 订单发票Model +/// +public class PddBrowserOrderInvoiceViewModel : BindableBaseEx +{ + + public string buyerId { get; set; } // 买手Id + public string buyerName { get; set; } // 买手名称 + /// + /// 订单价 + /// + public int order_amount { get; set; } + /// + /// 实付款 + /// + public string display_amount { get; set; } + /// + /// 下单时间 + /// + public long order_time { get; set; } + /// + /// 订单号 + /// + public string order_sn { get; set; } + + public int status { get; set; } + public int pay_status { get; set; } + public string order_status_prompt { get; set; } + public List order_Goods { get; set; } + + + public List order_buttons { get; set; } + + + public string GoodsName { get => order_Goods?.FirstOrDefault()?.goods_name ?? ""; } + public bool IsInvoiced + { + get => order_buttons?.Any(a => a.button_code == 500) ?? false; + } + + public int Quantity => order_Goods?.Sum(a => a.goods_number.Value) ?? 0; + /// 发票状态文案:已开票 / 待开票 + public string InvoiceStatusText => IsInvoiced ? "已开票" : "待开票"; + public DateTime OrderTime + { + get => DateTimeHelper.ConvertFromUnixTimestampInSeconds(order_time); + } + public string ThumbUrl=> order_Goods?.FirstOrDefault()?.thumb_url ?? ""; + public string DisplayAmount => (order_amount / 100.0).ToString("F2"); +} + +public class OrderButtonItem +{ + public int button_code { get; set; } + public string brief_prompt { get; set; } + public ButtonTypeValue type_value { get; set; } +} +public class ButtonTypeValue +{ + public string Url { get; set; } +} \ No newline at end of file diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs new file mode 100644 index 0000000..c661fa1 --- /dev/null +++ b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs @@ -0,0 +1,168 @@ +using _29WxOrderWpf.CefHelper; +using _29WxOrderWpf.Commands; +using AllBase; +using CefSharp; +using CefSharp.Handler; +using CefSharp.Wpf; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using Work._29Tools.CefTools; + +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(); + + + 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(); + } + + public ICommand CloseOrderBrowserCommand => new DelegateCommand(HidenOrderBrowser); + 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 IsAutoScroll + { + 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 (IsAutoScroll) return; + IsAutoScroll = true; + _cancellationTokenSource = new CancellationTokenSource(); + _ = autoScroll(_cancellationTokenSource.Token); + } + + // 停止滚动 + public void StopAutoScroll() + { + IsAutoScroll = false; + _cancellationTokenSource?.Cancel(); + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = null; + } + + private async Task autoScroll(CancellationToken token) + { + while (IsAutoScroll && !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")) + { + + } + } + +} diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs new file mode 100644 index 0000000..182c4b8 --- /dev/null +++ b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs @@ -0,0 +1,391 @@ +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 +} + diff --git a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml index 008a6df..a01248e 100644 --- a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml +++ b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml @@ -122,7 +122,7 @@ - + - + + + + @@ -307,11 +314,13 @@ Margin="0,-10,-10,0" HorizontalAlignment="Right" VerticalAlignment="Top" - Background="Transparent" Click="close" + Background="Transparent" + Click="close" Content="x" /> - Date: Thu, 20 Aug 2026 14:57:05 +0800 Subject: [PATCH 2/4] =?UTF-8?q?Revert=20"=E5=8F=91=E7=A5=A8=E5=8A=A9?= =?UTF-8?q?=E6=89=8B"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f2d31c4a42b0334c6458844157d3f7b6c050434c. --- .../ImageUrlToBitmapImageConverter.cs | 28 +- .../Ctrls/OrderCtrls/OrderListCtrl.Command.cs | 318 ------- .../Ctrls/OrderCtrls/OrderListCtrl.xaml | 42 +- .../Ctrls/OrderCtrls/OrderListCtrl.xaml.cs | 273 +++++- .../Ctrls/PDDInvoice/PDDInvoiceView.xaml | 800 ------------------ .../Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs | 37 - .../ViewModels/PDDInvoiceOrderModel.cs | 70 -- .../ViewModels/PDDInvoiceViewModel.Browser.cs | 168 ---- .../ViewModels/PDDInvoiceViewModel.cs | 391 --------- .../Statistics/ShopRevenueStatisticsView.xaml | 27 +- 10 files changed, 304 insertions(+), 1850 deletions(-) delete mode 100644 29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs delete mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml delete mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs delete mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs delete mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs delete mode 100644 29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs diff --git a/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs b/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs index 2063aaf..dfbf7e4 100644 --- a/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs +++ b/29WxOrderWpf/Converters/ImageUrlToBitmapImageConverter.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -15,38 +14,27 @@ namespace _29WxOrderWpf.Converters { public class ImageUrlToBitmapImageConverter : IValueConverter { - /// 缓存上限,防止大量缩略图重复下载导致内存膨胀 - private const int MaxCacheCount = 200; - - private readonly ConcurrentDictionary _imageCache = new ConcurrentDictionary(); - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is string url && Uri.IsWellFormedUriString(url, UriKind.Absolute)) { - if (_imageCache.TryGetValue(url, out BitmapImage cached)) - { - return cached; - } - try { // 直接加载绑定如果遇到有问题的网络图片会直接崩溃。 - BitmapImage bitMap = AllBase.ImageBuild.LoadBitmipImageFromUrl(url); - if (bitMap != null) - { - if (_imageCache.Count >= MaxCacheCount) - { - _imageCache.Clear(); - } - _imageCache[url] = bitMap; - } + //var bitMap = new BitmapImage(new Uri(url)); + BitmapImage bitMap = null; + //bitMap = LoadImageFromUrl(url + "?imageView2/1/w/100/format/webp|imageMogr2/auto-orient="); + bitMap = AllBase.ImageBuild.LoadBitmipImageFromUrl(url); return bitMap; + //string errStr = ""; + //var bitmapImg = GetUrlImg(url, out errStr); + //return bitmapImg; } catch { } + //return Task.Run(() => new BitmapImage(new Uri(url))); // 使用 Task.Run 来异步加载图片。 } return null; } diff --git a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs deleted file mode 100644 index 6625d74..0000000 --- a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.Command.cs +++ /dev/null @@ -1,318 +0,0 @@ -using _29WxOrderWpf.BaseWindows; -using _29WxOrderWpf.Commands; -using _29WxOrderWpf.Common; -using _29WxOrderWpf.Ctrls.PDDInvoice; -using _29WxOrderWpf.Ctrls.Statistics; -using _29WxOrderWpf.Services; -using AllBase.Helper; -using AllBase.Model.DBModel; -using NaiBa.Util.Extension; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; -using Work._29Tools.BLL; -using static _29WxOrderWpf.Services.ShipGiftService; - -namespace _29WxOrderWpf.Ctrls.OrderCtrls; - -public partial class OrderListCtrl -{ - #region 统计 - private DialogWindow _statisticsDialog; - public ICommand ShowShopRevenueStatisticsDialogViewCommand => new DelegateCommand(ShowShopRevenueStatisticsDialogView); - - private void ShowShopRevenueStatisticsDialogView() - { - if (_statisticsDialog == null) - { - _statisticsDialog = new DialogWindow() - { - Title = "统计", - Content = new ShopRevenueStatisticsView(), - - }; - _statisticsDialog.Closed += (s, e) => _statisticsDialog = null; - } - _statisticsDialog.Show(); - } - #endregion - - #region 礼物 - public ICommand MultipleShipGiftCommand => new AsyncDelegateCommand(MultipleShipGift); - /// - /// 批量发送礼品单 - /// - /// - /// - - private async Task MultipleShipGift() - { - - try - { - var list = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList(); - int count = list.Count; - if (count == 0) - { - BaseMsgWindow.ShowError("请选取要发货的订单", "Error"); - return; - } - - - GiftType giftType = GiftType._160; - if (cb_gift.SelectedIndex == 0) - { - giftType = GiftType._155; - } - else - { - giftType = GiftType._160; - } - int index = 1; - int sucessCount = 0; - int errorCount = 0; - foreach (oms_wei_order_info item in list) - { - try - { - var rst = await WxApiBLL.WxSearchAndDropshipCancelAsync(item.Shop, item); - if (rst == "success") - { - var ret = await _shipGiftService.Send(item.order_id, giftType); - if (ret) - { - sucessCount++; - item.gift_order_status = 1; - this.FilterOneOrder(item, true); - } - else - { - errorCount++; - } - } - else - { - errorCount++; - } - } - catch (Exception ex) - { - errorCount++; - } - finally - { - item.IsSelect = false; - } - - SetProgress(index, count); - BottomMsg = $"礼品单发送进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}"; - index++; - } - - BottomMsg = $"礼品单发送完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}"; - } - catch (Exception ex) - { - BaseMsgWindow.ShowError("礼品单发货失败\n" + ex.Message, "Error"); - } - finally - { - - } - } - #endregion - #region 同步订单 - /// - /// 拉取微信订单到任务列表 - /// - public ICommand PullWXOrderCommand => new AsyncDelegateCommand(PullWXOrder); - - private async Task PullWXOrder() - { - try - { - var isAfterSales = GlobalConfig.OrderTabHeaderStr.StartsWith("需处理售后单");//是否售后 - - var selectedShops = GlobalConfig.ShopLoginList.Where(a => a.IsSelect).ToList(); - if (selectedShops.Count == 0) - { - selectedShops = GlobalConfig.ShopLoginList.ToList(); - } - - var selectedOrders = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList(); - int count = selectedOrders.Count; - if (count > 0 && isAfterSales == false)//非售后订单 - { - if (BaseMsgWindow.ShowConfirm($"已选取:{count}个订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; - BottomMsg = $"订单同步进度...."; - int index = 1; - int sucessCount = 0; - int errorCount = 0; - foreach (var item in selectedOrders) - { - var ret = await PullWXOrderService.Instance.PullOrderDetailAsync(item.shop_id, item.order_id); ; - if (ret) - { - sucessCount++; - this.GetOrder(item.order_id); - SetProgress(index, count); - item.IsSelect = false; - } - else - { - errorCount++; - } - BottomMsg = $"订单同步进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}"; - index++; - } - BottomMsg = $"订单同步进度完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}"; - } - else if (count > 0 && isAfterSales == true)//售后订单 - { - if (BaseMsgWindow.ShowConfirm($"已选取:{count}个售后订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; - //var dictionaryResult = selectedOrders - // .Where(o => o?.refundItems != null) - // .SelectMany(o => o.refundItems - // .Where(item => item != null) - // .Select(item => new { o.shop_id, item.after_sale_order_id })) - // .GroupBy(x => x.shop_id) - // .ToDictionary( - // g => g.Key, - // g => g.Select(x => x.after_sale_order_id).ToArray() - // ); - - - //BottomMsg = $"售后订单同步进度...."; - //foreach (var item in dictionaryResult) - //{ - // var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(item.Key, item.Value); - //} - //BottomMsg = $"售后同步任务已发送,等待同步完成"; - - - - int index = 1; - int sucessCount = 0; - int errorCount = 0; - BottomMsg = $"售后订单同步进度...."; - foreach (KeyValuePair> item in selectedOrders.GroupBy(a => a.shop_id).ToDictionary(a => a.Key, a => a.ToList())) - { - long shopid = item.Key; - string shopName = item.Value.FirstOrDefault()?.shop_name ?? ""; - string[] afterSaleOrderIds = item.Value.SelectMany(a => a.refundItems).Where(a => a != null).Select(a => a.after_sale_order_id).ToArray(); - var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(shopid, afterSaleOrderIds); - if (ret) - { - sucessCount++; - SetProgress(index, count); - item.Value.ForEach(a => a.IsSelect = false); - } - else - { - errorCount++; - } - BottomMsg = $"售后订单同步进度:{index}/{count}\t\t{shopName}"; - index++; - - } - BottomMsg = $"售后同步任务已发送,等待同步完成"; - } - else - { - count = selectedShops.Count; - string prefix = $"已选取:{count}个商铺"; - if (count == GlobalConfig.ShopLoginList.Count) - { - prefix = "已选取全部商铺"; - } - - - var startTime = dateStart.SelectedDate.Value; - var endTime = dateEnd.SelectedDate.Value; - - string msg = ""; - if (isAfterSales) - { - msg = $"{prefix}"; - } - else - { - msg = $"{prefix}\n\n时间范围:{startTime.ToString("yyyy-MM-dd")}-{endTime.ToString("yyyy-MM-dd")}"; - } - - if (BaseMsgWindow.ShowConfirm(msg, $"{(isAfterSales ? "售后" : "")}同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return; - - if ((endTime - startTime).Days > 7) - { - throw new Exception("时间范围最大7天"); - } - - var ret = false; - if (isAfterSales) - { - ret = await PullWXOrderService.Instance.PullRefundOrderByShopsAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime); - } - else - { - ret = await PullWXOrderService.Instance.PullOrderByShopIdsAndTimeRangeAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime); - } - if (ret) - { - BaseMsgWindow.ShowInfo("同步任务已发送,等待同步完成\n任务详情查看任务列表"); - } - else - { - BaseMsgWindow.ShowError("同步任务失败"); - } - } - - - } - catch (Exception ex) - { - BaseMsgWindow.ShowError("同步订单失败\n" + ex.Message, "Error"); - } - //var service = PullWXOrderService.Instance; - //foreach (var item in list) - //{ - // await service.PullOrderDetailAsync(item.shop_id, item.order_id); - //} - } - #endregion - #region 显示任务列表 - private DialogWindow _taskDialog; - public ICommand ShowTaskDialogViewCommand => new DelegateCommand(ShowTaskDialogView); - - private void ShowTaskDialogView() - { - if (_taskDialog == null) - { - _taskDialog = new DialogWindow() - { - Title = "任务列表", - Content = new OrderTaskDialogView(), - - }; - _taskDialog.Closed += (s, e) => _taskDialog = null; - } - _taskDialog.Show(); - } - #endregion - - #region 拼多多发票 - public ICommand ShowPDDInvoiceDialogCommand => new DelegateCommand(ShowPDDInvoiceDialog); - - private void ShowPDDInvoiceDialog() - { - new DialogWindow - { - Title = "发票助手", - Content = new PDDInvoiceView() - }.ShowDialog(); - } - #endregion -} diff --git a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml index 129ea92..c36abb5 100644 --- a/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml +++ b/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl.xaml @@ -25,8 +25,7 @@ - - + @@ -41,8 +40,11 @@ + + + + - @@ -203,8 +205,7 @@ Padding="4" Click="btnFilter_Click" Content="过滤" - Style="{StaticResource BasePageButtonStyle}" - ToolTip="过滤" /> + Style="{StaticResource BasePageButtonStyle}" /> - - + - - - - - - - - - \ No newline at end of file diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs b/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs deleted file mode 100644 index 0e640ac..0000000 --- a/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceView.xaml.cs +++ /dev/null @@ -1,37 +0,0 @@ -using _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace _29WxOrderWpf.Ctrls.PDDInvoice; - -/// -/// PDDInvoiceView.xaml 的交互逻辑 -/// -public partial class PDDInvoiceView : UserControl -{ - public PDDInvoiceView() - { - InitializeComponent(); - DataContext = new PDDInvoiceViewModel(); - } - - private void txtSearch_KeyDown(object sender, KeyEventArgs e) - { - if (e.Key == Key.Enter && DataContext is PDDInvoiceViewModel viewModel) - { - viewModel.SearchCommand.Execute(null); - } - } -} \ No newline at end of file diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs deleted file mode 100644 index 128ff3a..0000000 --- a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceOrderModel.cs +++ /dev/null @@ -1,70 +0,0 @@ -using AllBase.Model.Result; -using System; -using System.Collections.Generic; -using System.Linq; -using WPFCommon.Helpers; -using WPFCommon.Models; - -namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels; - -/// -/// 订单发票Model -/// -public class PddBrowserOrderInvoiceViewModel : BindableBaseEx -{ - - public string buyerId { get; set; } // 买手Id - public string buyerName { get; set; } // 买手名称 - /// - /// 订单价 - /// - public int order_amount { get; set; } - /// - /// 实付款 - /// - public string display_amount { get; set; } - /// - /// 下单时间 - /// - public long order_time { get; set; } - /// - /// 订单号 - /// - public string order_sn { get; set; } - - public int status { get; set; } - public int pay_status { get; set; } - public string order_status_prompt { get; set; } - public List order_Goods { get; set; } - - - public List order_buttons { get; set; } - - - public string GoodsName { get => order_Goods?.FirstOrDefault()?.goods_name ?? ""; } - public bool IsInvoiced - { - get => order_buttons?.Any(a => a.button_code == 500) ?? false; - } - - public int Quantity => order_Goods?.Sum(a => a.goods_number.Value) ?? 0; - /// 发票状态文案:已开票 / 待开票 - public string InvoiceStatusText => IsInvoiced ? "已开票" : "待开票"; - public DateTime OrderTime - { - get => DateTimeHelper.ConvertFromUnixTimestampInSeconds(order_time); - } - public string ThumbUrl=> order_Goods?.FirstOrDefault()?.thumb_url ?? ""; - public string DisplayAmount => (order_amount / 100.0).ToString("F2"); -} - -public class OrderButtonItem -{ - public int button_code { get; set; } - public string brief_prompt { get; set; } - public ButtonTypeValue type_value { get; set; } -} -public class ButtonTypeValue -{ - public string Url { get; set; } -} \ No newline at end of file diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs deleted file mode 100644 index c661fa1..0000000 --- a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.Browser.cs +++ /dev/null @@ -1,168 +0,0 @@ -using _29WxOrderWpf.CefHelper; -using _29WxOrderWpf.Commands; -using AllBase; -using CefSharp; -using CefSharp.Handler; -using CefSharp.Wpf; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Input; -using Work._29Tools.CefTools; - -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(); - - - 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(); - } - - public ICommand CloseOrderBrowserCommand => new DelegateCommand(HidenOrderBrowser); - 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 IsAutoScroll - { - 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 (IsAutoScroll) return; - IsAutoScroll = true; - _cancellationTokenSource = new CancellationTokenSource(); - _ = autoScroll(_cancellationTokenSource.Token); - } - - // 停止滚动 - public void StopAutoScroll() - { - IsAutoScroll = false; - _cancellationTokenSource?.Cancel(); - _cancellationTokenSource?.Dispose(); - _cancellationTokenSource = null; - } - - private async Task autoScroll(CancellationToken token) - { - while (IsAutoScroll && !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")) - { - - } - } - -} diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs deleted file mode 100644 index 182c4b8..0000000 --- a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs +++ /dev/null @@ -1,391 +0,0 @@ -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 -} - diff --git a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml index a01248e..008a6df 100644 --- a/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml +++ b/29WxOrderWpf/Ctrls/Statistics/ShopRevenueStatisticsView.xaml @@ -122,7 +122,7 @@ - + - - - - + @@ -314,13 +307,11 @@ Margin="0,-10,-10,0" HorizontalAlignment="Right" VerticalAlignment="Top" - Background="Transparent" - Click="close" + Background="Transparent" Click="close" Content="x" /> - Date: Thu, 20 Aug 2026 15:45:32 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=BA=9B=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=A4=9A=E5=BA=97=E9=93=BA=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E8=BF=94=E5=9B=9E=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 29WxOrderWpf/Converters/OrderTaskStatusConverter.cs | 2 ++ .../Ctrls/OrderCtrls/OrderTaskDialogView.xaml | 3 +++ .../Ctrls/OrderCtrls/OrderTaskDialogView.xaml.cs | 2 +- 29WxOrderWpf/Services/PullWXOrderService.cs | 13 ++++++++++++- Work/ERP.API/Orders/PullWXOrderServiceApi.cs | 7 +++---- Work/ERP.API/TaskStatus.cs | 4 +++- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/29WxOrderWpf/Converters/OrderTaskStatusConverter.cs b/29WxOrderWpf/Converters/OrderTaskStatusConverter.cs index d852de0..cd86425 100644 --- a/29WxOrderWpf/Converters/OrderTaskStatusConverter.cs +++ b/29WxOrderWpf/Converters/OrderTaskStatusConverter.cs @@ -23,6 +23,8 @@ namespace _29WxOrderWpf.Converters return "已完成"; case TaskStatus.ManuallyInterrupted: return "已中断"; + case TaskStatus.Fail: + return "执行失败"; } } return value?.ToString() ?? string.Empty; diff --git a/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml b/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml index 309113b..c4ec8f5 100644 --- a/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml +++ b/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml @@ -187,6 +187,9 @@ + + + diff --git a/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml.cs b/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml.cs index d211e2a..b93fd23 100644 --- a/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml.cs +++ b/29WxOrderWpf/Ctrls/OrderCtrls/OrderTaskDialogView.xaml.cs @@ -109,7 +109,7 @@ public class OrderTaskDialogViewModel : BindableBaseEx, IDisposable if (IsShowAll == true) return true; - return task.Status == 1 || task.Status == 3; + return task.Status !=2; } /// 任务列表 diff --git a/29WxOrderWpf/Services/PullWXOrderService.cs b/29WxOrderWpf/Services/PullWXOrderService.cs index a69bae0..3ab2374 100644 --- a/29WxOrderWpf/Services/PullWXOrderService.cs +++ b/29WxOrderWpf/Services/PullWXOrderService.cs @@ -91,10 +91,21 @@ namespace _29WxOrderWpf.Services public async Task GetTaskStatus() { var tasks = await _kjdApi.GetWxTaskStatus(); + if (tasks != null) { Tasks.Clear(); - tasks.ForEach(a => Tasks.Add(a)); + tasks.ForEach(a => + { + if (!string.IsNullOrEmpty(a.TaskFailReason)) + { + if (a.TaskFailReason.Contains("任务执行异常")) + { + a.Status = 4; + } + } + Tasks.Add(a); + }); } } diff --git a/Work/ERP.API/Orders/PullWXOrderServiceApi.cs b/Work/ERP.API/Orders/PullWXOrderServiceApi.cs index cae7049..2eaa7a4 100644 --- a/Work/ERP.API/Orders/PullWXOrderServiceApi.cs +++ b/Work/ERP.API/Orders/PullWXOrderServiceApi.cs @@ -94,7 +94,7 @@ namespace Work.ERP.API.Orders startTime = startTime.ToString("yyyy-MM-dd HH:mm:ss"), endTime = endTime.ToString("yyyy-MM-dd HH:mm:ss"), clientUserName = BaseClass.UserName, - remark=$"同步 {startTime.ToString("yyyy-MM-dd")}/{endTime.ToString("dd")}" + remark = $"同步 {startTime.ToString("yyyy-MM-dd")}/{endTime.ToString("dd")}" }); var result = await PostAndGetTaskIdAsync("/prod-api/api/oms-api/client/sync/pull_order", data); @@ -104,7 +104,7 @@ namespace Work.ERP.API.Orders } else { - string msg = string.Join("\n", result.Data.Select(a => $"{a.shopName},{a.message}")); + string msg = string.Join("\n", result.Data.Select(a => $"{a.shopName},任务正在执行中")); throw new Exception(msg); } } @@ -136,7 +136,7 @@ namespace Work.ERP.API.Orders } else { - string msg = string.Join("\n", result.Data.Select(a => $"{a.shopName},{a.message}")); + string msg = string.Join("\n", result.Data.Select(a => $"{a.shopName},任务正在执行中")); throw new Exception(msg); } } @@ -179,7 +179,6 @@ namespace Work.ERP.API.Orders private async Task PostAndGetTaskIdAsync(string url, string data) { var result = await ERPHttp.e57PostResponseAsync(url, data); - if (result.Code != 200) throw new Exception(result.Msg); return result; } } diff --git a/Work/ERP.API/TaskStatus.cs b/Work/ERP.API/TaskStatus.cs index 73503ba..7f876d1 100644 --- a/Work/ERP.API/TaskStatus.cs +++ b/Work/ERP.API/TaskStatus.cs @@ -21,6 +21,8 @@ namespace Work.ERP.API /// 已人为中断 /// [Description("已人为中断")] - ManuallyInterrupted = 3 + ManuallyInterrupted = 3, + [Description("失败")] + Fail = 4 } } From 772ee833c83768fbdbdf8f16f7ae698069657415 Mon Sep 17 00:00:00 2001 From: chfei Date: Thu, 20 Aug 2026 15:58:36 +0800 Subject: [PATCH 4/4] =?UTF-8?q?Debug=20=E4=B8=8D=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Work/Initialization.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Work/Initialization.cs b/Work/Initialization.cs index 8361e49..7c22506 100644 --- a/Work/Initialization.cs +++ b/Work/Initialization.cs @@ -43,11 +43,13 @@ namespace Work BaseClass.IsMainCompany = true; } BaseClass.IsBuyer = FileBase.Exists(Application.StartupPath + "\\buyer.ini"); - Task.Run(() => { CheckUpdate(); }); - //new Thread(Update).Start();//--------检查更新 - //new Thread(GetAuthConfig).Start(); - //new Thread(new JumpUpProductNew().Ini).Start(); - new Thread(CheckFiles).Start(); +#if !DEBUG + Task.Run(() => { CheckUpdate(); }); +#endif + //new Thread(Update).Start();//--------检查更新 + //new Thread(GetAuthConfig).Start(); + //new Thread(new JumpUpProductNew().Ini).Start(); + new Thread(CheckFiles).Start(); //new Thread(UpdateTime).Start(); //new Thread(GetMacCode).Start(); @@ -92,7 +94,7 @@ namespace Work } - #region 获取IP + #region 获取IP public static void GetPublicIp() { try @@ -133,7 +135,7 @@ namespace Work } } - #endregion + #endregion /// /// 检查更新 @@ -334,7 +336,7 @@ namespace Work } - #region 同步系统时间 + #region 同步系统时间 [DllImport("kernel32.dll", SetLastError = true)] public static extern int SetLocalTime(ref SystemTime lpSystemTime); @@ -372,7 +374,7 @@ namespace Work } } - #endregion + #endregion /// /// 检查文件 @@ -575,7 +577,7 @@ namespace Work FileBase.WriteAllText(ConfigFilePach, content, Encoding.UTF8); } - #region JS + #region JS public static string JsCode = @"(function(f){if(typeof exports===""object""&&typeof module!==""undefined""){module.exports=f()}else if(typeof define===""function""&&define.amd){define([],f)}else{var g;if(typeof window!==""undefined""){g=window}else if(typeof global!==""undefined""){g=global}else if(typeof self!==""undefined""){g=self}else{g=this}g.pako = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==""function""&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(""Cannot find module '""+o+""'"");throw f.code=""MODULE_NOT_FOUND"",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==""function""&&require;for(var o=0;o