900 lines
23 KiB
C#
900 lines
23 KiB
C#
using _29WxOrderWpf.BaseWindows;
|
|
using _29WxOrderWpf.CefHelper;
|
|
using _29WxOrderWpf.Commands;
|
|
using _29WxOrderWpf.Common;
|
|
using _29WxOrderWpf.Ctrls.Statistics;
|
|
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 MAX.Core.Helpers;
|
|
using NaiBa.Util.Extension;
|
|
using Newtonsoft.Json;
|
|
using NPOI.SS.Formula.Functions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Data;
|
|
using System.Windows.Input;
|
|
using System.Windows.Threading;
|
|
using Work._29Tools.CefTools;
|
|
using Work.BaseForms;
|
|
using WPFCommon.Converters;
|
|
using WPFCommon.Helpers;
|
|
using WPFCommon.Models;
|
|
using WxOrder.Framework.Helpers;
|
|
|
|
namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels;
|
|
|
|
/// <summary>
|
|
/// 拼多多发票助手 视图模型
|
|
/// </summary>
|
|
public partial class PDDInvoiceViewModel : BindableBaseEx
|
|
{
|
|
private const string ConfigPath = "./invoice.config";
|
|
private List<OrderInvoiceInfo> OrderInvoiceInfoList = new();
|
|
private readonly HashSet<string> _orderSns = new();
|
|
private string _searchText = "";
|
|
private PddBrowserOrderInvoiceViewModel _selectedOrder;
|
|
private bool _isInvoiceDialogOpen;
|
|
private bool _isInvoiceDetailOpen;
|
|
private string _invoiceTitle = "";
|
|
private string _taxNo = "";
|
|
private CancellationTokenSource _cancellationTokenSource;
|
|
private InvoiceConfig Config { get; set; }
|
|
/// <summary> 订单列表 </summary>
|
|
public ObservableCollection<PddBrowserOrderInvoiceViewModel> Orders { get; }
|
|
public ICollectionView OrdersView { get; }
|
|
public PDDInvoiceViewModel()
|
|
{
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
Config = NaiBa.Util.Helper.ConfigHelper.LoadConfig<InvoiceConfig>(ConfigPath);
|
|
Orders = new ObservableCollection<PddBrowserOrderInvoiceViewModel>();
|
|
Orders.CollectionChanged += Orders_CollectionChanged;
|
|
OrdersView = CollectionViewSource.GetDefaultView(Orders);
|
|
OrdersView.Filter = FilterPredicate;
|
|
OrdersView.SortDescriptions.Add(
|
|
new SortDescription(nameof(PddBrowserOrderInvoiceViewModel.order_time), ListSortDirection.Ascending));
|
|
|
|
BuyerLoginList = GlobalConfig.PDDBuyerLoginList;
|
|
//Orders = new ObservableCollection<PDDInvoiceOrderModel>(_allOrders);
|
|
|
|
|
|
InitBrowser();
|
|
if (Config == null) Config = new InvoiceConfig();
|
|
|
|
EndTime = DateTime.Now;
|
|
StartTime = EndTime.AddMonths(-1);
|
|
if (EnvironmentHelper.IsTest)
|
|
{
|
|
Config.Title = "嵩县雷神商贸有限责任公司";
|
|
Config.TaxNo = "91410325MADQERT68E";
|
|
Config.MaxAmount = 99;
|
|
_ = InitSampleData();
|
|
}
|
|
}
|
|
private bool FilterPredicate(object obj)
|
|
{
|
|
if (obj is not PddBrowserOrderInvoiceViewModel order) return false;
|
|
|
|
// 发票状态过滤
|
|
bool? temp = InvoiceStatus == 0 ? null : InvoiceStatus == 2;
|
|
if (temp.HasValue && order.IsInvoiced != temp.Value)
|
|
return false;
|
|
|
|
// 关键字过滤
|
|
var keyword = SearchText?.Trim();
|
|
if (!IsKeywordMatch(order, keyword))
|
|
return false;
|
|
if (order.OrderTime < StartTime || EndTime < order.OrderTime) return false;
|
|
return true;
|
|
}
|
|
partial void InitBrowser();
|
|
|
|
/// <summary> 列表增删时订阅/退订订单勾选状态,用于刷新表头全选状态 </summary>
|
|
private void Orders_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
if (e.NewItems != null)
|
|
{
|
|
foreach (PddBrowserOrderInvoiceViewModel item in e.NewItems)
|
|
{
|
|
item.PropertyChanged += Order_PropertyChanged;
|
|
}
|
|
}
|
|
if (e.OldItems != null)
|
|
{
|
|
foreach (PddBrowserOrderInvoiceViewModel item in e.OldItems)
|
|
{
|
|
item.PropertyChanged -= Order_PropertyChanged;
|
|
}
|
|
}
|
|
RefreshSelectAllState();
|
|
}
|
|
|
|
private void Order_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == nameof(PddBrowserOrderInvoiceViewModel.IsSelected))
|
|
{
|
|
RefreshSelectAllState();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ObservableCollectionThreadSafe<BuyerLoginInfo> BuyerLoginList { get; set; } = new ObservableCollectionThreadSafe<BuyerLoginInfo>();
|
|
|
|
|
|
private void InvoiceStatusChanged()
|
|
{
|
|
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
|
|
/// <summary> 搜索关键字:订单号 / 商品名称 / 买家 </summary>
|
|
public string SearchText
|
|
{
|
|
get => _searchText;
|
|
set => SetProperty(ref _searchText, value, nameof(SearchText));
|
|
}
|
|
public int InvoiceStatus
|
|
{
|
|
get => GetValue<int>();
|
|
set => SetValue(value, InvoiceStatusChanged);
|
|
}
|
|
public DateTime StartTime
|
|
{
|
|
get => GetValue<DateTime>();
|
|
set => SetValue(value);
|
|
}
|
|
public DateTime EndTime
|
|
{
|
|
get => GetValue<DateTime>();
|
|
set => SetValue(value);
|
|
}
|
|
|
|
/// <summary> 开票弹窗是否打开 </summary>
|
|
public bool IsOrderListDialogOpen
|
|
{
|
|
get => GetValue<bool>();
|
|
set
|
|
{
|
|
SetValue(value);
|
|
if (value)
|
|
{
|
|
ShowOrderBrowser();
|
|
}
|
|
else
|
|
{
|
|
HidenOrderBrowser();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary> 发票详情弹窗是否打开 </summary>
|
|
public bool IsInvoiceDetailOpen
|
|
{
|
|
get => _isInvoiceDetailOpen;
|
|
set => SetProperty(ref _isInvoiceDetailOpen, value, nameof(IsInvoiceDetailOpen));
|
|
}
|
|
|
|
/// <summary> 当前操作的订单 </summary>
|
|
public PddBrowserOrderInvoiceViewModel SelectedOrder
|
|
{
|
|
get => _selectedOrder;
|
|
set => SetProperty(ref _selectedOrder, value, nameof(SelectedOrder));
|
|
}
|
|
|
|
///// <summary> 发票抬头 </summary>
|
|
//public string InvoiceTitle
|
|
//{
|
|
// get => _invoiceTitle;
|
|
// set => SetProperty(ref _invoiceTitle, value, nameof(InvoiceTitle));
|
|
//}
|
|
|
|
///// <summary> 税号 </summary>
|
|
//public string TaxNo
|
|
//{
|
|
// get => _taxNo;
|
|
// set => SetProperty(ref _taxNo, value, nameof(TaxNo));
|
|
//}
|
|
/// <summary>
|
|
/// 开始开票总金额
|
|
/// </summary>
|
|
public decimal AmountTotal
|
|
{
|
|
get => GetValue<decimal>();
|
|
set => SetValue(value);
|
|
}
|
|
///// <summary>
|
|
///// 最大开票金额
|
|
///// </summary>
|
|
//public decimal MaxAmount
|
|
//{
|
|
// get => GetValue<decimal>();
|
|
// set => SetValue(value);
|
|
//}
|
|
/// <summary>
|
|
/// 已开票金额
|
|
/// </summary>
|
|
public decimal InvoicedAmountTotal
|
|
{
|
|
get => GetValue<decimal>();
|
|
set => SetValue(value);
|
|
}
|
|
/// <summary>
|
|
/// 未开票金额
|
|
/// </summary>
|
|
public decimal UninvoicedAmountTotal
|
|
{
|
|
get => GetValue<decimal>();
|
|
set => SetValue(value);
|
|
}
|
|
|
|
public bool IsLoadImage
|
|
{
|
|
get => GetValue<bool>();
|
|
set => SetValue(value);
|
|
}
|
|
|
|
|
|
|
|
|
|
public ICommand SearchCommand => new DelegateCommand(Search);
|
|
|
|
public ICommand ResetCommand => new DelegateCommand(ResetSearch);
|
|
|
|
public ICommand OpenInvoiceCommand => new DelegateCommand<PddBrowserOrderInvoiceViewModel>(OpenInvoice);
|
|
|
|
public ICommand ShowInvoiceCommand => new DelegateCommand<PddBrowserOrderInvoiceViewModel>(ShowInvoice);
|
|
|
|
public ICommand ViewOrderCommand => new DelegateCommand<PddBrowserOrderInvoiceViewModel>(ViewOrder);
|
|
|
|
|
|
|
|
public ICommand ReadOrderCommand => new AsyncDelegateCommand(ReadOrder);
|
|
|
|
private async Task ReadOrder()
|
|
{
|
|
if (SelectedBuyer == null)
|
|
{
|
|
BaseMsgWindow.ShowError("未填选择买手号");
|
|
return;
|
|
}
|
|
Debug.WriteLine("开始读单");
|
|
BottomMsg = $"开始读取订单";
|
|
StartProgress();
|
|
try
|
|
{
|
|
if (!IsReadOrder)
|
|
{
|
|
_orderSns.Clear();
|
|
Orders.Clear();
|
|
OrderInvoiceInfoList.Clear();
|
|
|
|
|
|
|
|
string path = string.Format(inviceDataPath, SelectedBuyer.buyer_id);
|
|
if (File.Exists(NaiBa.Util.Helper.ConfigHelper.GetConfigUserPath(path)))
|
|
{
|
|
var ret = BaseMsgWindow.ShowConfirm("检测到已有历史数据是否加载?").DialogResult;
|
|
if (ret == true)
|
|
{
|
|
var data = NaiBa.Util.Helper.ConfigHelper.LoadConfig<List<OrderInvoiceInfo>>(path);
|
|
AddOrders(data.Select(a => new PddBrowserOrderInvoiceViewModel(a)));
|
|
BottomMsg = $"已加载历史数据";
|
|
return;
|
|
}
|
|
else if (ret == null)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
Browser.Load("https://mobile.yangkeduo.com/orders.html");
|
|
await Task.Delay(Timeout.Infinite, _cancellationTokenSource.Token);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
catch (TaskCanceledException)
|
|
{
|
|
Debug.WriteLine("停止读单");
|
|
}
|
|
//ShowOrderBrowser();
|
|
}
|
|
|
|
public ICommand StopReadOrderCommand => new AsyncDelegateCommand(StopReadOrder);
|
|
private async Task StopReadOrder()
|
|
{
|
|
StopAutoScroll();
|
|
CompleteProgress();
|
|
}
|
|
|
|
|
|
#region 勾选 / 全选 / 反选
|
|
public int SelectedCount
|
|
{
|
|
get => GetValue<int>();
|
|
set => SetValue(value);
|
|
}
|
|
private bool? _isSelectAll;
|
|
private bool _isUpdatingSelectAll;
|
|
|
|
/// <summary> 表头全选状态(三态:null 表示部分选中) </summary>
|
|
public bool? IsSelectAll
|
|
{
|
|
get => _isSelectAll;
|
|
set
|
|
{
|
|
if (_isSelectAll == value) return;
|
|
_isSelectAll = value;
|
|
RaisePropertyChanged(nameof(IsSelectAll));
|
|
if (_isUpdatingSelectAll) return;
|
|
if (value == true)
|
|
{
|
|
foreach (var order in Orders)
|
|
{
|
|
if (order.IsInvoiced == false)
|
|
{
|
|
order.IsSelected = true;
|
|
}
|
|
}
|
|
}
|
|
else if (value == false)
|
|
{
|
|
foreach (var order in Orders) order.IsSelected = false;
|
|
}
|
|
RefreshSelectAllState();
|
|
}
|
|
}
|
|
|
|
public ICommand InvertSelectionCommand => new DelegateCommand(InvertSelection);
|
|
|
|
/// <summary> 反选当前可见列表 </summary>
|
|
private void InvertSelection()
|
|
{
|
|
foreach (var order in Orders) order.IsSelected = !order.IsSelected;
|
|
RefreshSelectAllState();
|
|
}
|
|
|
|
/// <summary> 根据当前可见列表的勾选情况刷新表头全选状态 </summary>
|
|
private void RefreshSelectAllState()
|
|
{
|
|
_isUpdatingSelectAll = true;
|
|
try
|
|
{
|
|
if (Orders.Count == 0)
|
|
{
|
|
IsSelectAll = false;
|
|
return;
|
|
}
|
|
int selected = Orders.Count(o => o.IsSelected);
|
|
IsSelectAll = selected == 0 ? false : selected == Orders.Count ? true : (bool?)null;
|
|
SelectedCount = selected;
|
|
}
|
|
finally
|
|
{
|
|
_isUpdatingSelectAll = false;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 批量开票
|
|
|
|
private bool _isBatchInvoicing;
|
|
/// <summary> 是否正在批量开票 </summary>
|
|
public bool IsBatchInvoicing
|
|
{
|
|
get => _isBatchInvoicing;
|
|
set => SetProperty(ref _isBatchInvoicing, value, nameof(IsBatchInvoicing));
|
|
}
|
|
|
|
/// <summary> 当前正在批量处理的订单,页面脚本执行完成后通过它回传结果 </summary>
|
|
private TaskCompletionSource<bool> _currentInvoiceTcs;
|
|
|
|
public ICommand BatchInvoiceCommand => new AsyncDelegateCommand(BatchInvoice);
|
|
|
|
/// <summary>
|
|
/// 批量开票:统计勾选的待开票订单 → 确认 → 后台逐单自动开票
|
|
/// </summary>
|
|
private async Task BatchInvoice()
|
|
{
|
|
if (IsBatchInvoicing) return;
|
|
|
|
if (string.IsNullOrEmpty(Config.Title) || string.IsNullOrEmpty(Config.TaxNo))
|
|
{
|
|
BaseMsgWindow.ShowError("未填写公司或税号");
|
|
return;
|
|
}
|
|
|
|
var targets = OrdersView.Cast<PddBrowserOrderInvoiceViewModel>().Where(o => o.IsSelected && !o.IsInvoiced).ToList();
|
|
if (targets.Count == 0)
|
|
{
|
|
BaseMsgWindow.ShowError("请先勾选需要开票的订单");
|
|
return;
|
|
}
|
|
if (Config.MaxAmount <= 0)
|
|
{
|
|
BaseMsgWindow.ShowError("请填写开票总金额");
|
|
return;
|
|
}
|
|
var confirm = BaseMsgWindow.ShowConfirm(
|
|
$"已勾选 {targets.Count} 个待开票订单,确定开始批量开票吗?\n请确认发票抬头与税号无误。\n开票总金额:{Config.MaxAmount}",
|
|
"批量开票");
|
|
if (confirm.DialogResult != true) return;
|
|
|
|
//Config.Title = InvoiceTitle;
|
|
//Config.TaxNo = TaxNo;
|
|
//Config.MaxAmount = MaxAmount;
|
|
//NaiBa.Util.Helper.ConfigHelper.SaveConfig(ConfigPath, Config);
|
|
|
|
await BatchInvoiceAsync(targets);
|
|
}
|
|
|
|
public ICommand StopBatchInvoiceCommand => new AsyncDelegateCommand(StopBatchInvoice);
|
|
|
|
private async Task StopBatchInvoice()
|
|
{
|
|
IsBatchInvoicing = false;
|
|
}
|
|
|
|
public ICommand ShowSettingDialogCommand => new DelegateCommand(ShowSettingDialog);
|
|
|
|
private void ShowSettingDialog()
|
|
{
|
|
var view = new PDDInvoiceDialog();
|
|
new DialogWindow
|
|
{
|
|
Title = "设置",
|
|
Content = view,
|
|
}.ShowDialog();
|
|
Config = view.Config;
|
|
}
|
|
|
|
public event EventHandler<int> BatchInvoiceChanged;
|
|
/// <summary>
|
|
/// 后台批量开票:逐单加载开票页并自动填写提交,底部进度条实时更新,成功后更新列表状态
|
|
/// </summary>
|
|
private async Task BatchInvoiceAsync(List<PddBrowserOrderInvoiceViewModel> targets)
|
|
{
|
|
IsBatchInvoicing = true;
|
|
AmountTotal = 0;
|
|
int success = 0, fail = 0;
|
|
try
|
|
{
|
|
ProgressMaximum = targets.Count;
|
|
ProgressValue = 0;
|
|
BottomMsg = $"正在批量开票:0/{targets.Count}";
|
|
|
|
for (int i = 0; i < targets.Count; i++)
|
|
{
|
|
if (IsBatchInvoicing == false)
|
|
{
|
|
BottomMsg = "已取消批量开票";
|
|
return;
|
|
}
|
|
|
|
if (AmountTotal >= Config.MaxAmount)
|
|
{
|
|
return;
|
|
}
|
|
var order = targets[i];
|
|
BottomMsg = $"正在批量开票:{i}/{targets.Count},当前订单:{order.order_sn}";
|
|
ProgressValue = i;
|
|
SelectedOrder = order;
|
|
BatchInvoiceChanged?.Invoke(this, OrdersView.Cast<PddBrowserOrderInvoiceViewModel>().ToList().IndexOf(order));
|
|
bool ok = false;
|
|
if (EnvironmentHelper.IsTest)
|
|
{
|
|
ok = true;
|
|
await Task.Delay(1000);
|
|
}
|
|
else
|
|
{
|
|
_currentInvoiceTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
BrowserDetail.Load($"https://mobile.yangkeduo.com/transac_return_compensation.html?_t_timestamp=transac_modify_invoice&order_sn={order.order_sn}");
|
|
|
|
// 等待页面脚本执行完成(最长 60 秒)
|
|
var done = await Task.WhenAny(_currentInvoiceTcs.Task, Task.Delay(TimeSpan.FromSeconds(60)));
|
|
ok = done == _currentInvoiceTcs.Task && _currentInvoiceTcs.Task.Result;
|
|
}
|
|
if (ok)
|
|
{
|
|
order.IsInvoiced = true;
|
|
order.IsSelected = false;
|
|
success++;
|
|
AmountTotal += order.order_amount / 100m;
|
|
}
|
|
else
|
|
{
|
|
fail++;
|
|
}
|
|
ProgressValue = success + fail;
|
|
BottomMsg = $"正在批量开票:{i}/{targets.Count},当前订单:{order.order_sn}。总金额:{AmountTotal.ToString("N2")}";
|
|
BottomRMsg = $"批量开票状态:成功 {success} 个,失败 {fail} 个。总金额:{AmountTotal.ToString("N2")}";
|
|
StatisticsInvoiceAmount();
|
|
await Task.Delay(1000);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
fail = targets.Count - success;
|
|
BaseMsgWindow.ShowError("批量开票异常:" + ex.Message);
|
|
}
|
|
finally
|
|
{
|
|
_currentInvoiceTcs = null;
|
|
ProgressMaximum = targets.Count;
|
|
ProgressValue = targets.Count;
|
|
IsBatchInvoicing = false;
|
|
BaseMsgWindow.ShowInfo(BottomMsg);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 统计发票金额
|
|
/// </summary>
|
|
private void StatisticsInvoiceAmount()
|
|
{
|
|
InvoicedAmountTotal = OrdersView.Cast<PddBrowserOrderInvoiceViewModel>().Where(a => a.IsInvoiced).Sum(a => a.order_amount) / 100m;
|
|
UninvoicedAmountTotal = OrdersView.Cast<PddBrowserOrderInvoiceViewModel>().Where(a => a.IsInvoiced == false).Sum(a => a.order_amount) / 100m;
|
|
}
|
|
#endregion
|
|
|
|
|
|
/// <summary> 按 订单号 / 商品名称 过滤订单 </summary>
|
|
private void Search()
|
|
{
|
|
OrdersView.Refresh();
|
|
StatisticsInvoiceAmount();
|
|
//var keyword = SearchText?.Trim();
|
|
//bool? _tempIsInvoiced = InvoiceStatus == 0 ? null : InvoiceStatus == 2;
|
|
//foreach (var order in Orders)
|
|
//{
|
|
// if (_tempIsInvoiced.HasValue)
|
|
// {
|
|
// if (order.IsInvoiced != _tempIsInvoiced.Value) continue;
|
|
// }
|
|
// if (!IsKeywordMatch(order, keyword))
|
|
// {
|
|
// continue;
|
|
// }
|
|
// 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 = "";
|
|
InvoiceStatus = 0;
|
|
EndTime = DateTime.Now;
|
|
StartTime = EndTime.AddMonths(-1);
|
|
Search();
|
|
}
|
|
/// <summary>
|
|
/// 申请开票
|
|
/// </summary>
|
|
/// <param name="order"></param>
|
|
private void OpenInvoice(PddBrowserOrderInvoiceViewModel order)
|
|
{
|
|
SelectedOrder = order;
|
|
if (string.IsNullOrEmpty(Config.Title) || string.IsNullOrEmpty(Config.TaxNo))
|
|
{
|
|
BaseMsgWindow.ShowError("未填写公司或税号");
|
|
return;
|
|
}
|
|
BrowserDetail.Load($"https://mobile.yangkeduo.com/transac_return_compensation.html?_t_timestamp=transac_modify_invoice&order_sn={order.order_sn}");
|
|
ShowOrderBrowserDetail();
|
|
}
|
|
|
|
private void ShowInvoice(PddBrowserOrderInvoiceViewModel order)
|
|
{
|
|
SelectedOrder = order;
|
|
BrowserDetail.Load($"https://mobile.yangkeduo.com/transac_return_compensation.html?_t_timestamp=transac_invoice&order_sn={order.order_sn}");
|
|
ShowOrderBrowserDetail();
|
|
}
|
|
|
|
private void ViewOrder(PddBrowserOrderInvoiceViewModel order)
|
|
{
|
|
SelectedOrder = order;
|
|
BrowserDetail.Load($"https://mobile.yangkeduo.com/{order.order_link_url}");
|
|
ShowOrderBrowserDetail();
|
|
//MessageBox.Show($"查看订单:{order.OrderNo}");
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 数据解析
|
|
|
|
private void parserData(string data)
|
|
{
|
|
List<PddBrowserOrderInvoiceViewModel> list = JsonHelper.DeserializeJsonToList<PddBrowserOrderInvoiceViewModel>(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);
|
|
BottomMsg = $"正在读取订单,读取日期{matched.Last().OrderTime.ToString("yyyy-MM-dd")}";
|
|
}));
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary> 将新订单写入总表,并按当前搜索关键字决定是否加入可见列表(自动去重) </summary>
|
|
private void AddOrders(IEnumerable<PddBrowserOrderInvoiceViewModel> items)
|
|
{
|
|
var keyword = SearchText?.Trim();
|
|
foreach (var item in items)
|
|
{
|
|
if (!string.IsNullOrEmpty(item.order_sn) && !_orderSns.Add(item.order_sn))
|
|
{
|
|
continue;
|
|
}
|
|
if (item.IsInvoiced == false)
|
|
{
|
|
item.IsInvoiced = item.order_buttons?.Any(a => a.brief_prompt == "发票详情") ?? false;
|
|
}
|
|
Orders.Add(item);
|
|
|
|
if (Config.IsSaveData)
|
|
{
|
|
OrderInvoiceInfoList.Add(new OrderInvoiceInfo
|
|
{
|
|
GoodsName = item.GoodsName,
|
|
order_amount = item.order_amount,
|
|
order_time = item.order_time,
|
|
order_sn = item.order_sn,
|
|
order_link_url = item.order_link_url,
|
|
IsInvoiced = item.IsInvoiced,
|
|
ThumbUrl = item.ThumbUrl
|
|
});
|
|
}
|
|
}
|
|
StatisticsInvoiceAmount();
|
|
|
|
|
|
SaveOrderInvoiceInfo();
|
|
}
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 原型演示数据(后续可替换为真实接口数据)
|
|
/// </summary>
|
|
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)
|
|
{
|
|
|
|
}
|
|
}
|
|
Orders.FirstOrDefault().IsInvoiced = true;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private const string inviceDataPath = "inviceData_{0}";
|
|
/// <summary>
|
|
/// 保存数据
|
|
/// </summary>
|
|
private void SaveOrderInvoiceInfo()
|
|
{
|
|
if (SelectedBuyer == null) return;
|
|
string path = string.Format(inviceDataPath, SelectedBuyer.buyer_id);
|
|
NaiBa.Util.Helper.ConfigHelper.SaveConfig<List<OrderInvoiceInfo>>(path, OrderInvoiceInfoList);
|
|
}
|
|
private void GetOrderInvoiceInfo()
|
|
{
|
|
if (SelectedBuyer == null) return;
|
|
string path = string.Format(inviceDataPath, SelectedBuyer.buyer_id);
|
|
if (File.Exists(NaiBa.Util.Helper.ConfigHelper.GetConfigUserPath(path)))
|
|
{
|
|
if (BaseMsgWindow.ShowConfirm("检测到已有旧数据是否加载?").DialogResult == true)
|
|
{
|
|
var data = NaiBa.Util.Helper.ConfigHelper.LoadConfig<List<OrderInvoiceInfo>>(path);
|
|
AddOrders(data.Select(a => new PddBrowserOrderInvoiceViewModel(a)));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#region 进度条
|
|
|
|
private string _bottomMsg = "";
|
|
public string BottomMsg
|
|
{
|
|
get => _bottomMsg;
|
|
set => SetValue(ref _bottomMsg, value);
|
|
}
|
|
|
|
private string _bottomRMsg = "";
|
|
public string BottomRMsg
|
|
{
|
|
get => _bottomRMsg;
|
|
set => SetValue(ref _bottomRMsg, 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;
|
|
|
|
/// <summary>
|
|
/// 开始未知总数的百分比模拟进度:80% 之前走得快,越到最后走得越慢,
|
|
/// 理论上永远走不到 95% 以上,直到调用 <see cref="CompleteProgress"/> 才会变成 100%。
|
|
/// </summary>
|
|
public void StartProgress()
|
|
{
|
|
StopUnknownTotalProgressTimer();
|
|
ProgressMaximum = 100;
|
|
ProgressValue = 0;
|
|
_unknownTotalProgressStartTime = DateTime.Now;
|
|
_unknownTotalProgressTimer = new System.Threading.Timer(_ => UpdateUnknownTotalProgress(), null, 0, 200);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 结束进度:停止模拟,进度条立即变为 100%。
|
|
/// </summary>
|
|
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
|
|
}
|
|
|
|
public class InvoiceConfig
|
|
{
|
|
public string Title { get; set; }
|
|
public string TaxNo { get; set; }
|
|
public decimal MaxAmount { get; set; }
|
|
public bool IsSaveData { get; set; }
|
|
} |